LCOV - code coverage report
Current view: top level - dev/pci - puc.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 150 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: puc.c,v 1.26 2018/05/02 19:11:01 phessler Exp $       */
       2             : /*      $NetBSD: puc.c,v 1.3 1999/02/06 06:29:54 cgd Exp $      */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1996, 1998, 1999
       6             :  *      Christopher G. Demetriou.  All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 3. All advertising materials mentioning features or use of this software
      17             :  *    must display the following acknowledgement:
      18             :  *      This product includes software developed by Christopher G. Demetriou
      19             :  *      for the NetBSD Project.
      20             :  * 4. The name of the author may not be used to endorse or promote products
      21             :  *    derived from this software without specific prior written permission
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      24             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      25             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      26             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      27             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      28             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      29             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      30             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      31             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      32             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      33             :  */
      34             : 
      35             : /*
      36             :  * PCI "universal" communication card device driver, glues com, lpt,
      37             :  * and similar ports to PCI via bridge chip often much larger than
      38             :  * the devices being glued.
      39             :  *
      40             :  * Author: Christopher G. Demetriou, May 14, 1998 (derived from NetBSD
      41             :  * sys/dev/pci/pciide.c, revision 1.6).
      42             :  *
      43             :  * These devices could be (and some times are) described as
      44             :  * communications/{serial,parallel}, etc. devices with known
      45             :  * programming interfaces, but those programming interfaces (in
      46             :  * particular the BAR assignments for devices, etc.) in fact are not
      47             :  * particularly well defined.
      48             :  *
      49             :  * After I/we have seen more of these devices, it may be possible
      50             :  * to generalize some of these bits.  In particular, devices which
      51             :  * describe themselves as communications/serial/16[45]50, and
      52             :  * communications/parallel/??? might be attached via direct
      53             :  * 'com' and 'lpt' attachments to pci.
      54             :  */
      55             : 
      56             : #include <sys/param.h>
      57             : #include <sys/systm.h>
      58             : #include <sys/device.h>
      59             : #include <sys/tty.h>
      60             : 
      61             : #include <dev/pci/pcireg.h>
      62             : #include <dev/pci/pcivar.h>
      63             : #include <dev/pci/pucvar.h>
      64             : 
      65             : #include <dev/ic/comreg.h>
      66             : #include <dev/ic/comvar.h>
      67             : 
      68             : struct puc_pci_softc {
      69             :         struct puc_softc        sc_psc;
      70             : 
      71             :         pci_chipset_tag_t       pc;
      72             :         pci_intr_handle_t       ih;
      73             : };
      74             : 
      75             : int     puc_pci_match(struct device *, void *, void *);
      76             : void    puc_pci_attach(struct device *, struct device *, void *);
      77             : int     puc_pci_detach(struct device *, int);
      78             : const char *puc_pci_intr_string(struct puc_attach_args *);
      79             : void    *puc_pci_intr_establish(struct puc_attach_args *, int,
      80             :     int (*)(void *), void *, char *);
      81             : 
      82             : struct cfattach puc_pci_ca = {
      83             :         sizeof(struct puc_pci_softc), puc_pci_match,
      84             :         puc_pci_attach, puc_pci_detach
      85             : };
      86             : 
      87             : struct cfdriver puc_cd = {
      88             :         NULL, "puc", DV_DULL
      89             : };
      90             : 
      91             : const char *puc_port_type_name(int);
      92             : 
      93             : int
      94           0 : puc_pci_match(struct device *parent, void *match, void *aux)
      95             : {
      96           0 :         struct pci_attach_args *pa = aux;
      97             :         const struct puc_device_description *desc;
      98             :         pcireg_t bhlc, subsys;
      99             : 
     100           0 :         bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
     101           0 :         if (PCI_HDRTYPE_TYPE(bhlc) != 0)
     102           0 :                 return (0);
     103             : 
     104           0 :         subsys = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
     105             : 
     106           0 :         desc = puc_find_description(PCI_VENDOR(pa->pa_id),
     107           0 :             PCI_PRODUCT(pa->pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys));
     108           0 :         if (desc != NULL)
     109           0 :                 return (1);
     110             : 
     111           0 :         return (0);
     112           0 : }
     113             : 
     114             : const char *
     115           0 : puc_pci_intr_string(struct puc_attach_args *paa)
     116             : {
     117           0 :         struct puc_pci_softc *sc = paa->puc;
     118             : 
     119           0 :         return (pci_intr_string(sc->pc, sc->ih));
     120             : }
     121             : 
     122             : void *
     123           0 : puc_pci_intr_establish(struct puc_attach_args *paa, int type,
     124             :     int (*func)(void *), void *arg, char *name)
     125             : {
     126           0 :         struct puc_pci_softc *sc = paa->puc;
     127           0 :         struct puc_softc *psc = &sc->sc_psc;
     128             :         
     129           0 :         psc->sc_ports[paa->port].intrhand =
     130           0 :             pci_intr_establish(sc->pc, sc->ih, type, func, arg, name);
     131             : 
     132           0 :         return (psc->sc_ports[paa->port].intrhand);
     133             : }
     134             : 
     135             : void
     136           0 : puc_pci_attach(struct device *parent, struct device *self, void *aux)
     137             : {
     138           0 :         struct puc_pci_softc *psc = (struct puc_pci_softc *)self;
     139           0 :         struct puc_softc *sc = &psc->sc_psc;
     140           0 :         struct pci_attach_args *pa = aux;
     141           0 :         struct puc_attach_args paa;
     142             :         pcireg_t subsys;
     143             :         int i;
     144             : 
     145           0 :         subsys = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
     146           0 :         sc->sc_desc = puc_find_description(PCI_VENDOR(pa->pa_id),
     147           0 :             PCI_PRODUCT(pa->pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys));
     148             : 
     149           0 :         puc_print_ports(sc->sc_desc);
     150             : 
     151           0 :         for (i = 0; i < PUC_NBARS; i++) {
     152           0 :                 pcireg_t type;
     153             :                 int bar;
     154             : 
     155           0 :                 sc->sc_bar_mappings[i].mapped = 0;
     156           0 :                 bar = PCI_MAPREG_START + 4 * i;
     157           0 :                 if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, bar, &type))
     158           0 :                         continue;
     159             : 
     160           0 :                 sc->sc_bar_mappings[i].mapped = (pci_mapreg_map(pa, bar, type,
     161           0 :                     0, &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h,
     162           0 :                     &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s, 0)
     163           0 :                       == 0);
     164           0 :                 if (sc->sc_bar_mappings[i].mapped)
     165           0 :                         continue;
     166             : 
     167             :                 /*
     168             :                  * If a port on this card is used as serial console,
     169             :                  * mapping the associated BAR will fail because the
     170             :                  * bus space is already mapped.  In that case, we try
     171             :                  * to re-use the already existing mapping.
     172             :                  * Unfortunately this means that if a BAR is used to
     173             :                  * support multiple ports, only the first port will
     174             :                  * work.
     175             :                  */
     176           0 :                 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, type,
     177           0 :                     &sc->sc_bar_mappings[i].a, NULL, NULL) == 0 &&
     178           0 :                     pa->pa_iot == comconsiot &&
     179           0 :                     sc->sc_bar_mappings[i].a == comconsaddr) {
     180           0 :                         sc->sc_bar_mappings[i].t = comconsiot;
     181           0 :                         sc->sc_bar_mappings[i].h = comconsioh;
     182           0 :                         sc->sc_bar_mappings[i].s = COM_NPORTS;
     183           0 :                         sc->sc_bar_mappings[i].mapped = 1;
     184           0 :                         continue;
     185             :                 }
     186             : 
     187           0 :                 printf("%s: couldn't map BAR at offset 0x%lx\n",
     188           0 :                     sc->sc_dev.dv_xname, (long)bar);
     189           0 :         }
     190             : 
     191             :         /* Map interrupt. */
     192           0 :         psc->pc = pa->pa_pc;
     193           0 :         if (pci_intr_map(pa, &psc->ih)) {
     194           0 :                 printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
     195           0 :                 return;
     196             :         }
     197             : 
     198           0 :         paa.puc = sc;
     199           0 :         paa.intr_string = &puc_pci_intr_string;
     200           0 :         paa.intr_establish = &puc_pci_intr_establish;
     201             : 
     202           0 :         puc_common_attach(sc, &paa);
     203           0 : }
     204             : 
     205             : void
     206           0 : puc_common_attach(struct puc_softc *sc, struct puc_attach_args *paa)
     207             : {
     208           0 :         const struct puc_device_description *desc = sc->sc_desc;
     209             :         int i, bar;
     210             : 
     211             :         /* Configure each port. */
     212           0 :         for (i = 0; i < PUC_MAX_PORTS; i++) {
     213           0 :                 if (desc->ports[i].type == 0)        /* neither com or lpt */
     214             :                         continue;
     215             :                 /* make sure the base address register is mapped */
     216           0 :                 bar = PUC_PORT_BAR_INDEX(desc->ports[i].bar);
     217           0 :                 if (!sc->sc_bar_mappings[bar].mapped) {
     218           0 :                         printf("%s: %s port uses unmapped BAR (0x%x)\n",
     219           0 :                             sc->sc_dev.dv_xname,
     220           0 :                             puc_port_type_name(desc->ports[i].type),
     221           0 :                             desc->ports[i].bar);
     222           0 :                         continue;
     223             :                 }
     224             : 
     225             :                 /* set up to configure the child device */
     226           0 :                 paa->port = i;
     227           0 :                 paa->a = sc->sc_bar_mappings[bar].a;
     228           0 :                 paa->t = sc->sc_bar_mappings[bar].t;
     229             : 
     230           0 :                 paa->type = desc->ports[i].type;
     231             : 
     232           0 :                 if (desc->ports[i].offset >= sc->sc_bar_mappings[bar].s ||
     233           0 :                     bus_space_subregion(sc->sc_bar_mappings[bar].t,
     234           0 :                     sc->sc_bar_mappings[bar].h, desc->ports[i].offset,
     235           0 :                     sc->sc_bar_mappings[bar].s - desc->ports[i].offset,
     236           0 :                     &paa->h)) {
     237           0 :                         printf("%s: couldn't get subregion for port %d\n",
     238           0 :                             sc->sc_dev.dv_xname, i);
     239           0 :                         continue;
     240             :                 }
     241             : 
     242             : #if 0
     243             :                 if (autoconf_verbose)
     244             :                         printf("%s: port %d: %s @ (index %d) 0x%x "
     245             :                             "(0x%lx, 0x%lx)\n", sc->sc_dev.dv_xname, paa->port,
     246             :                             puc_port_type_name(paa->type), bar, (int)paa->a,
     247             :                             (long)paa->t, (long)paa->h);
     248             : #endif
     249             : 
     250             :                 /* and configure it */
     251           0 :                 sc->sc_ports[i].dev = config_found_sm(&sc->sc_dev, paa,
     252             :                     puc_print, puc_submatch);
     253           0 :         }
     254           0 : }
     255             : 
     256             : int
     257           0 : puc_pci_detach(struct device *self, int flags)
     258             : {
     259           0 :         struct puc_pci_softc *sc = (struct puc_pci_softc *)self;
     260           0 :         struct puc_softc *psc = &sc->sc_psc;
     261             :         int i, rv;
     262             : 
     263           0 :         for (i = PUC_MAX_PORTS; i--; ) {
     264           0 :                 if (psc->sc_ports[i].intrhand)
     265           0 :                         pci_intr_disestablish(sc->pc,
     266             :                             psc->sc_ports[i].intrhand);
     267           0 :                 if (psc->sc_ports[i].dev)
     268           0 :                         if ((rv = config_detach(psc->sc_ports[i].dev, flags)))
     269           0 :                                 return (rv);
     270             :         }
     271             : 
     272           0 :         for (i = PUC_NBARS; i--; )
     273           0 :                 if (psc->sc_bar_mappings[i].mapped)
     274           0 :                         bus_space_unmap(psc->sc_bar_mappings[i].t,
     275           0 :                             psc->sc_bar_mappings[i].h,
     276           0 :                             psc->sc_bar_mappings[i].s);
     277             : 
     278           0 :         return (0);
     279           0 : }
     280             : 
     281             : int
     282           0 : puc_print(void *aux, const char *pnp)
     283             : {
     284           0 :         struct puc_attach_args *paa = aux;
     285             : 
     286           0 :         if (pnp)
     287           0 :                 printf("%s at %s", puc_port_type_name(paa->type), pnp);
     288           0 :         printf(" port %d", paa->port);
     289           0 :         return (UNCONF);
     290             : }
     291             : 
     292             : int
     293           0 : puc_submatch(struct device *parent, void *vcf, void *aux)
     294             : {
     295           0 :         struct cfdata *cf = (struct cfdata *)vcf;
     296           0 :         struct puc_attach_args *aa = aux;
     297             : 
     298           0 :         if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != aa->port)
     299           0 :                 return 0;
     300           0 :         return ((*cf->cf_attach->ca_match)(parent, cf, aux));
     301           0 : }
     302             : 
     303             : const struct puc_device_description *
     304           0 : puc_find_description(u_int16_t vend, u_int16_t prod,
     305             :     u_int16_t svend, u_int16_t sprod)
     306             : {
     307             :         int i;
     308             : 
     309           0 :         for (i = 0; i < puc_ndevs; i++)
     310           0 :                 if ((vend & puc_devs[i].rmask[0]) == puc_devs[i].rval[0] &&
     311           0 :                     (prod & puc_devs[i].rmask[1]) == puc_devs[i].rval[1] &&
     312           0 :                     (svend & puc_devs[i].rmask[2]) == puc_devs[i].rval[2] &&
     313           0 :                     (sprod & puc_devs[i].rmask[3]) == puc_devs[i].rval[3])
     314           0 :                         return (&puc_devs[i]);
     315             : 
     316           0 :         return (NULL);
     317           0 : }
     318             : 
     319             : const char *
     320           0 : puc_port_type_name(int type)
     321             : {
     322             : 
     323           0 :         if (PUC_IS_COM(type))
     324           0 :                 return "com";
     325           0 :         if (PUC_IS_LPT(type))
     326           0 :                 return "lpt";
     327           0 :         return (NULL);
     328           0 : }
     329             : 
     330             : void
     331           0 : puc_print_ports(const struct puc_device_description *desc)
     332             : {
     333             :         int i, ncom, nlpt;
     334             : 
     335           0 :         printf(": ports: ");
     336           0 :         for (i = ncom = nlpt = 0; i < PUC_MAX_PORTS; i++) {
     337           0 :                 if (PUC_IS_COM(desc->ports[i].type))
     338           0 :                         ncom++;
     339           0 :                 else if (PUC_IS_LPT(desc->ports[i].type))
     340           0 :                         nlpt++;
     341             :         }
     342           0 :         if (ncom)
     343           0 :                 printf("%d com", ncom);
     344           0 :         if (nlpt) {
     345           0 :                 if (ncom)
     346           0 :                         printf(", ");
     347           0 :                 printf("%d lpt", nlpt);
     348           0 :         }
     349           0 :         printf("\n");
     350           0 : }

Generated by: LCOV version 1.13