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: releng/9.0/sys/dev/puc/puc.c 223091 2011-06-14 18:19:48Z jhb $");
   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 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_detach(port->p_dev) == 0) {
  416                         device_delete_child(dev, port->p_dev);
  417                         if (port->p_rres != NULL)
  418                                 rman_release_resource(port->p_rres);
  419                         if (port->p_ires != NULL)
  420                                 rman_release_resource(port->p_ires);
  421                 } else
  422                         error = ENXIO;
  423         }
  424         if (error)
  425                 return (error);
  426 
  427         if (sc->sc_serdevs != 0UL)
  428                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  429         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
  430 
  431         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
  432                 bar = &sc->sc_bar[idx];
  433                 if (bar->b_res != NULL)
  434                         bus_release_resource(sc->sc_dev, bar->b_type,
  435                             bar->b_rid, bar->b_res);
  436         }
  437 
  438         rman_fini(&sc->sc_irq);
  439         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
  440         rman_fini(&sc->sc_iomem);
  441         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
  442         rman_fini(&sc->sc_ioport);
  443         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
  444         free(sc->sc_port, M_PUC);
  445         return (0);
  446 }
  447 
  448 int
  449 puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
  450 {
  451         struct puc_softc *sc;
  452         intptr_t res;
  453         int error;
  454 
  455         sc = device_get_softc(dev);
  456         sc->sc_dev = dev;
  457         sc->sc_cfg = cfg;
  458 
  459         /* We don't attach to single-port serial cards. */
  460         if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
  461                 return (EDOOFUS);
  462         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
  463         if (error)
  464                 return (error);
  465         error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
  466         if (error)
  467                 return (error);
  468         if (res != 0)
  469                 device_set_desc(dev, (const char *)res);
  470         return (BUS_PROBE_DEFAULT);
  471 }
  472 
  473 struct resource *
  474 puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
  475     u_long start, u_long end, u_long count, u_int flags)
  476 {
  477         struct puc_port *port;
  478         struct resource *res;
  479         device_t assigned, originator;
  480         int error;
  481 
  482         /* Get our immediate child. */
  483         originator = child;
  484         while (child != NULL && device_get_parent(child) != dev)
  485                 child = device_get_parent(child);
  486         if (child == NULL)
  487                 return (NULL);
  488 
  489         port = device_get_ivars(child);
  490         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  491 
  492         if (rid == NULL || *rid != 0)
  493                 return (NULL);
  494 
  495         /* We only support default allocations. */
  496         if (start != 0UL || end != ~0UL)
  497                 return (NULL);
  498 
  499         if (type == port->p_bar->b_type)
  500                 res = port->p_rres;
  501         else if (type == SYS_RES_IRQ)
  502                 res = port->p_ires;
  503         else
  504                 return (NULL);
  505 
  506         if (res == NULL)
  507                 return (NULL);
  508 
  509         assigned = rman_get_device(res);
  510         if (assigned == NULL)   /* Not allocated */
  511                 rman_set_device(res, originator);
  512         else if (assigned != originator)
  513                 return (NULL);
  514 
  515         if (flags & RF_ACTIVE) {
  516                 error = rman_activate_resource(res);
  517                 if (error) {
  518                         if (assigned == NULL)
  519                                 rman_set_device(res, NULL);
  520                         return (NULL);
  521                 }
  522         }
  523 
  524         return (res);
  525 }
  526 
  527 int
  528 puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
  529     struct resource *res)
  530 {
  531         struct puc_port *port;
  532         device_t originator;
  533 
  534         /* Get our immediate child. */
  535         originator = child;
  536         while (child != NULL && device_get_parent(child) != dev)
  537                 child = device_get_parent(child);
  538         if (child == NULL)
  539                 return (EINVAL);
  540 
  541         port = device_get_ivars(child);
  542         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  543 
  544         if (rid != 0 || res == NULL)
  545                 return (EINVAL);
  546 
  547         if (type == port->p_bar->b_type) {
  548                 if (res != port->p_rres)
  549                         return (EINVAL);
  550         } else if (type == SYS_RES_IRQ) {
  551                 if (res != port->p_ires)
  552                         return (EINVAL);
  553                 if (port->p_hasintr)
  554                         return (EBUSY);
  555         } else
  556                 return (EINVAL);
  557 
  558         if (rman_get_device(res) != originator)
  559                 return (ENXIO);
  560         if (rman_get_flags(res) & RF_ACTIVE)
  561                 rman_deactivate_resource(res);
  562         rman_set_device(res, NULL);
  563         return (0);
  564 }
  565 
  566 int
  567 puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
  568     u_long *startp, u_long *countp)
  569 {
  570         struct puc_port *port;
  571         struct resource *res;
  572         u_long start;
  573 
  574         /* Get our immediate child. */
  575         while (child != NULL && device_get_parent(child) != dev)
  576                 child = device_get_parent(child);
  577         if (child == NULL)
  578                 return (EINVAL);
  579 
  580         port = device_get_ivars(child);
  581         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  582 
  583         if (type == port->p_bar->b_type)
  584                 res = port->p_rres;
  585         else if (type == SYS_RES_IRQ)
  586                 res = port->p_ires;
  587         else
  588                 return (ENXIO);
  589 
  590         if (rid != 0 || res == NULL)
  591                 return (ENXIO);
  592 
  593         start = rman_get_start(res);
  594         if (startp != NULL)
  595                 *startp = start;
  596         if (countp != NULL)
  597                 *countp = rman_get_end(res) - start + 1;
  598         return (0);
  599 }
  600 
  601 int
  602 puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
  603     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
  604 {
  605         struct puc_port *port;
  606         struct puc_softc *sc;
  607         device_t originator;
  608         int i, isrc, serdev;
  609 
  610         sc = device_get_softc(dev);
  611 
  612         /* Get our immediate child. */
  613         originator = child;
  614         while (child != NULL && device_get_parent(child) != dev)
  615                 child = device_get_parent(child);
  616         if (child == NULL)
  617                 return (EINVAL);
  618 
  619         port = device_get_ivars(child);
  620         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  621 
  622         if (cookiep == NULL || res != port->p_ires)
  623                 return (EINVAL);
  624         /* We demand that serdev devices use filter_only interrupts. */
  625         if (ihand != NULL)
  626                 return (ENXIO);
  627         if (rman_get_device(port->p_ires) != originator)
  628                 return (ENXIO);
  629 
  630         /*
  631          * Have non-serdev ports handled by the bus implementation. It
  632          * supports multiple handlers for a single interrupt as it is,
  633          * so we wouldn't add value if we did it ourselves.
  634          */
  635         serdev = 0;
  636         if (port->p_type == PUC_TYPE_SERIAL) {
  637                 i = 0, isrc = SER_INT_OVERRUN;
  638                 while (i < PUC_ISRCCNT) {
  639                         port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
  640                         if (port->p_ihsrc[i] != NULL)
  641                                 serdev = 1;
  642                         i++, isrc <<= 1;
  643                 }
  644         }
  645         if (!serdev)
  646                 return (BUS_SETUP_INTR(device_get_parent(dev), originator,
  647                     sc->sc_ires, flags, filt, ihand, arg, cookiep));
  648 
  649         sc->sc_serdevs |= 1UL << (port->p_nr - 1);
  650 
  651         port->p_hasintr = 1;
  652         port->p_iharg = arg;
  653 
  654         *cookiep = port;
  655         return (0);
  656 }
  657 
  658 int
  659 puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
  660     void *cookie)
  661 {
  662         struct puc_port *port;
  663         struct puc_softc *sc;
  664         device_t originator;
  665         int i;
  666 
  667         sc = device_get_softc(dev);
  668 
  669         /* Get our immediate child. */
  670         originator = child;
  671         while (child != NULL && device_get_parent(child) != dev)
  672                 child = device_get_parent(child);
  673         if (child == NULL)
  674                 return (EINVAL);
  675 
  676         port = device_get_ivars(child);
  677         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  678 
  679         if (res != port->p_ires)
  680                 return (EINVAL);
  681         if (rman_get_device(port->p_ires) != originator)
  682                 return (ENXIO);
  683 
  684         if (!port->p_hasintr)
  685                 return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
  686                     sc->sc_ires, cookie));
  687 
  688         if (cookie != port)
  689                 return (EINVAL);
  690 
  691         port->p_hasintr = 0;
  692         port->p_iharg = NULL;
  693 
  694         for (i = 0; i < PUC_ISRCCNT; i++)
  695                 port->p_ihsrc[i] = NULL;
  696 
  697         return (0);
  698 }
  699 
  700 int
  701 puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  702 {
  703         struct puc_port *port;
  704 
  705         /* Get our immediate child. */
  706         while (child != NULL && device_get_parent(child) != dev)
  707                 child = device_get_parent(child);
  708         if (child == NULL)
  709                 return (EINVAL);
  710 
  711         port = device_get_ivars(child);
  712         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  713 
  714         if (result == NULL)
  715                 return (EINVAL);
  716 
  717         switch(index) {
  718         case PUC_IVAR_CLOCK:
  719                 *result = port->p_rclk;
  720                 break;
  721         case PUC_IVAR_TYPE:
  722                 *result = port->p_type;
  723                 break;
  724         default:
  725                 return (ENOENT);
  726         }
  727         return (0);
  728 }
  729 
  730 int
  731 puc_bus_print_child(device_t dev, device_t child)
  732 {
  733         struct puc_port *port;
  734         int retval;
  735 
  736         port = device_get_ivars(child);
  737         retval = 0;
  738 
  739         retval += bus_print_child_header(dev, child);
  740         retval += printf(" at port %d", port->p_nr);
  741         retval += bus_print_child_footer(dev, child);
  742 
  743         return (retval);
  744 }
  745 
  746 int
  747 puc_bus_child_location_str(device_t dev, device_t child, char *buf,
  748     size_t buflen)
  749 {
  750         struct puc_port *port;
  751 
  752         port = device_get_ivars(child);
  753         snprintf(buf, buflen, "port=%d", port->p_nr);
  754         return (0);
  755 }
  756 
  757 int
  758 puc_bus_child_pnpinfo_str(device_t dev, device_t child, char *buf,
  759     size_t buflen)
  760 {
  761         struct puc_port *port;
  762 
  763         port = device_get_ivars(child);
  764         snprintf(buf, buflen, "type=%d", port->p_type);
  765         return (0);
  766 }

Cache object: 75c833b8297f7e0ccdd4dbb308991aac


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