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/ic/upc.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 /* $NetBSD: upc.c,v 1.14 2008/04/08 12:07:27 cegger Exp $ */
    2 /*-
    3  * Copyright (c) 2000, 2003 Ben Harris
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    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  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   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  * upc - driver for C&T Universal Peripheral Controllers
   30  *
   31  * Supports:
   32  * 82C710 Universal Peripheral Controller
   33  * 82C711 Universal Peripheral Controller II
   34  * 82C721 Universal Peripheral Controller III (untested)
   35  *
   36  * The 82C710 is substantially different from its successors.
   37  * Functions that just handle the 82C710 are named upc1_*, which those
   38  * that handle the 82C711 and 82C721 are named upc2_*.
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __KERNEL_RCSID(0, "$NetBSD: upc.c,v 1.14 2008/04/08 12:07:27 cegger Exp $");
   43 
   44 #include <sys/param.h>
   45 #include <sys/device.h>
   46 #include <sys/systm.h>
   47 
   48 #include <sys/bus.h>
   49 
   50 #include <dev/ata/atavar.h> /* XXX needed by wdcvar.h */
   51 #include <dev/ic/comreg.h>
   52 #include <dev/ic/lptreg.h>
   53 #include <dev/ic/lptvar.h>
   54 #include <dev/ic/wdcreg.h>
   55 #include <dev/ic/wdcvar.h>
   56 #include <dev/ic/upcreg.h>
   57 #include <dev/ic/upcvar.h>
   58 
   59 #include "locators.h"
   60 
   61 /* Conventional port to use for 82C710 configuration */
   62 #define UPC1_PORT_CRI   0x390
   63 #define UPC1_PORT_CAP   (UPC1_PORT_CRI + 1)
   64 
   65 static int upc1_probe(struct upc_softc *);
   66 static void upc1_attach(struct upc_softc *);
   67 static void upc2_attach(struct upc_softc *);
   68 static void upc_found(struct upc_softc *, char const *, int, int,
   69                       struct upc_irqhandle *);
   70 static void upc_found2(struct upc_softc *, char const *, int, int, int, int,
   71                        struct upc_irqhandle *);
   72 static int upc_print(void *, char const *);
   73 static int upc2_com3_addr(int);
   74 static int upc2_com4_addr(int);
   75 
   76 void
   77 upc_attach(struct upc_softc *sc)
   78 {
   79 
   80         if (upc1_probe(sc))
   81                 upc1_attach(sc);
   82         else
   83                 upc2_attach(sc);
   84 }
   85 
   86 static int
   87 upc1_probe(struct upc_softc *sc)
   88 {
   89 
   90         return upc1_read_config(sc, UPC1_CFGADDR_CONFBASE) ==
   91             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT;
   92 }
   93 
   94 static void
   95 upc1_attach(struct upc_softc *sc)
   96 {
   97         u_int8_t cr[16];
   98         int i;
   99 
  100         aprint_normal(": 82C710\n");
  101         /* Dump configuration */
  102         for (i = 0; i < 16; i++)
  103                 cr[i] = upc1_read_config(sc, i);
  104 
  105         aprint_verbose_dev(&sc->sc_dev, "config state");
  106         for (i = 0; i < 16; i++)
  107                 aprint_verbose(" %02x", cr[i]);
  108         aprint_verbose("\n");
  109 
  110         /* FDC */
  111         if (cr[UPC1_CFGADDR_CRC] & UPC1_CRC_FDCEN)
  112                 upc_found(sc, "fdc", UPC_PORT_FDCBASE, 2, &sc->sc_fintr);
  113         /* IDE */
  114         if (cr[UPC1_CFGADDR_CRC] & UPC1_CRC_IDEEN)
  115                 upc_found2(sc, "wdc", UPC_PORT_IDECMDBASE, 8,
  116                            UPC_PORT_IDECTLBASE, 2, &sc->sc_wintr);
  117         /* Parallel */
  118         if (cr[UPC1_CFGADDR_CR0] & UPC1_CR0_PEN)
  119                 upc_found(sc, "lpt",
  120                     cr[UPC1_CFGADDR_PARBASE] << UPC1_PARBASE_SHIFT,
  121                     LPT_NPORTS, &sc->sc_pintr);
  122         /* UART */
  123         if (cr[UPC1_CFGADDR_CR0] & UPC1_CR0_SEN)
  124                 upc_found(sc, "com",
  125                     cr[UPC1_CFGADDR_UARTBASE] << UPC1_UARTBASE_SHIFT,
  126                     COM_NPORTS, &sc->sc_irq4);
  127         /* Mouse */
  128         /* XXX not yet supported */
  129 }
  130 
  131 static void
  132 upc2_attach(struct upc_softc *sc)
  133 {
  134         u_int8_t cr[5];
  135         int i;
  136 
  137         aprint_normal(": 82C711/82C721");
  138         /* Dump configuration */
  139         for (i = 0; i < 5; i++)
  140                 cr[i] = upc2_read_config(sc, i);
  141 
  142         aprint_verbose(", config state %02x %02x %02x %02x %02x",
  143                cr[0], cr[1], cr[2], cr[3], cr[4]);
  144         aprint_normal("\n");
  145 
  146         /* "Find" the attached devices */
  147         /* FDC */
  148         if (cr[0] & UPC2_CR0_FDC_ENABLE)
  149                 upc_found(sc, "fdc", UPC_PORT_FDCBASE, 2, &sc->sc_fintr);
  150         /* IDE */
  151         if (cr[0] & UPC2_CR0_IDE_ENABLE)
  152                 upc_found2(sc, "wdc", UPC_PORT_IDECMDBASE, 8,
  153                            UPC_PORT_IDECTLBASE, 2, &sc->sc_wintr);
  154         /* Parallel */
  155         switch (cr[1] & UPC2_CR1_LPT_MASK) {
  156         case UPC2_CR1_LPT_3BC:
  157                 upc_found(sc, "lpt", 0x3bc, LPT_NPORTS, &sc->sc_pintr);
  158                 break;
  159         case UPC2_CR1_LPT_378:
  160                 upc_found(sc, "lpt", 0x378, LPT_NPORTS, &sc->sc_pintr);
  161                 break;
  162         case UPC2_CR1_LPT_278:
  163                 upc_found(sc, "lpt", 0x278, LPT_NPORTS, &sc->sc_pintr);
  164                 break;
  165         }
  166         /* UART1 */
  167         if (cr[2] & UPC2_CR2_UART1_ENABLE) {
  168                 switch (cr[2] & UPC2_CR2_UART1_MASK) {
  169                 case UPC2_CR2_UART1_3F8:
  170                         upc_found(sc, "com", 0x3f8, COM_NPORTS, &sc->sc_irq4);
  171                         break;
  172                 case UPC2_CR2_UART1_2F8:
  173                         upc_found(sc, "com", 0x2f8, COM_NPORTS, &sc->sc_irq3);
  174                         break;
  175                 case UPC2_CR2_UART1_COM3:
  176                         upc_found(sc, "com", upc2_com3_addr(cr[1]), COM_NPORTS,
  177                                   &sc->sc_irq4);
  178                         break;
  179                 case UPC2_CR2_UART1_COM4:
  180                         upc_found(sc, "com", upc2_com4_addr(cr[1]), COM_NPORTS,
  181                                   &sc->sc_irq3);
  182                         break;
  183                 }
  184         }
  185         /* UART2 */
  186         if (cr[2] & UPC2_CR2_UART2_ENABLE) {
  187                 switch (cr[2] & UPC2_CR2_UART2_MASK) {
  188                 case UPC2_CR2_UART2_3F8:
  189                         upc_found(sc, "com", 0x3f8, COM_NPORTS, &sc->sc_irq4);
  190                         break;
  191                 case UPC2_CR2_UART2_2F8:
  192                         upc_found(sc, "com", 0x2f8, COM_NPORTS, &sc->sc_irq3);
  193                         break;
  194                 case UPC2_CR2_UART2_COM3:
  195                         upc_found(sc, "com", upc2_com3_addr(cr[1]), COM_NPORTS,
  196                                   &sc->sc_irq4);
  197                         break;
  198                 case UPC2_CR2_UART2_COM4:
  199                         upc_found(sc, "com", upc2_com4_addr(cr[1]), COM_NPORTS,
  200                                   &sc->sc_irq3);
  201                         break;
  202                 }
  203         }
  204 
  205 }
  206 
  207 static void
  208 upc_found(struct upc_softc *sc, char const *devtype, int offset, int size,
  209           struct upc_irqhandle *uih)
  210 {
  211         struct upc_attach_args ua;
  212         int locs[UPCCF_NLOCS];
  213 
  214         ua.ua_devtype = devtype;
  215         ua.ua_offset = offset;
  216         ua.ua_iot = sc->sc_iot;
  217         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset, size, &ua.ua_ioh);
  218         ua.ua_irqhandle = uih;
  219 
  220         locs[UPCCF_OFFSET] = offset;
  221 
  222         config_found_sm_loc(&sc->sc_dev, "upc", locs, &ua,
  223                             upc_print, config_stdsubmatch);
  224 }
  225 
  226 static void
  227 upc_found2(struct upc_softc *sc, char const *devtype, int offset, int size,
  228            int offset2, int size2, struct upc_irqhandle *uih)
  229 {
  230         struct upc_attach_args ua;
  231         int locs[UPCCF_NLOCS];
  232 
  233         ua.ua_devtype = devtype;
  234         ua.ua_offset = offset;
  235         ua.ua_iot = sc->sc_iot;
  236         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset, size, &ua.ua_ioh);
  237         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset2, size2,
  238                             &ua.ua_ioh2);
  239         ua.ua_irqhandle = uih;
  240 
  241         locs[UPCCF_OFFSET] = offset;
  242 
  243         config_found_sm_loc(&sc->sc_dev, "upc", locs, &ua,
  244                             upc_print, config_stdsubmatch);
  245 }
  246 
  247 void
  248 upc_intr_establish(struct upc_irqhandle *uih, int level, int (*func)(void *),
  249                    void *arg) {
  250 
  251         uih->uih_level = level;
  252         uih->uih_func = func;
  253         uih->uih_arg = arg;
  254         /* Actual MD establishment will be handled later by bus attachment. */
  255 }
  256 
  257 static int
  258 upc2_com3_addr(int cr1)
  259 {
  260 
  261         switch (cr1 & UPC2_CR1_COM34_MASK) {
  262         case UPC2_CR1_COM34_338_238:
  263                 return 0x338;
  264         case UPC2_CR1_COM34_3E8_2E8:
  265                 return 0x3e8;
  266         case UPC2_CR1_COM34_2E8_2E0:
  267                 return 0x2e8;
  268         case UPC2_CR1_COM34_220_228:
  269                 return 0x220;
  270         }
  271         return -1;
  272 }
  273 
  274 static int
  275 upc2_com4_addr(int cr1)
  276 {
  277 
  278         switch (cr1 & UPC2_CR1_COM34_MASK) {
  279         case UPC2_CR1_COM34_338_238:
  280                 return 0x238;
  281         case UPC2_CR1_COM34_3E8_2E8:
  282                 return 0x2e8;
  283         case UPC2_CR1_COM34_2E8_2E0:
  284                 return 0x2e0;
  285         case UPC2_CR1_COM34_220_228:
  286                 return 0x228;
  287         }
  288         return -1;
  289 }
  290 
  291 static int
  292 upc_print(void *aux, char const *pnp)
  293 {
  294         struct upc_attach_args *ua = aux;
  295 
  296         if (pnp)
  297                 aprint_normal("%s at %s", ua->ua_devtype, pnp);
  298         aprint_normal(" offset 0x%x", ua->ua_offset);
  299         return UNCONF;
  300 }
  301 
  302 int
  303 upc1_read_config(struct upc_softc *sc, int reg)
  304 {
  305         bus_space_tag_t iot = sc->sc_iot;
  306         bus_space_handle_t ioh = sc->sc_ioh;
  307         int retval;
  308 
  309         /* Switch into configuration mode. */
  310         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1, UPC1_CFGMAGIC_1);
  311         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_2);
  312         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_3);
  313         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2,
  314             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT);
  315         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1,
  316             (UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT) ^ 0xff);
  317 
  318         /* Read register. */
  319         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, reg);
  320         retval = bus_space_read_1(iot, ioh, UPC1_PORT_CAP);
  321 
  322         /* Leave configuration mode. */
  323         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, UPC1_CFGADDR_EXIT);
  324         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, 0);
  325         return retval;
  326 }
  327 
  328 void
  329 upc1_write_config(struct upc_softc *sc, int reg, int val)
  330 {
  331         bus_space_tag_t iot = sc->sc_iot;
  332         bus_space_handle_t ioh = sc->sc_ioh;
  333 
  334         /* Switch into configuration mode. */
  335         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1, UPC1_CFGMAGIC_1);
  336         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_2);
  337         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_3);
  338         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2,
  339             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT);
  340         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1,
  341             (UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT) ^ 0xff);
  342 
  343         /* Read register. */
  344         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, reg);
  345         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, val);
  346 
  347         /* Leave configuration mode. */
  348         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, UPC1_CFGADDR_EXIT);
  349         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, 0);
  350 }
  351 
  352 int
  353 upc2_read_config(struct upc_softc *sc, int reg)
  354 {
  355         bus_space_tag_t iot = sc->sc_iot;
  356         bus_space_handle_t ioh = sc->sc_ioh;
  357         int retval;
  358 
  359         /* Switch into configuration mode. */
  360         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  361         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  362 
  363         /* Read register. */
  364         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, reg);
  365         retval = bus_space_read_1(iot, ioh, UPC2_PORT_CFGDATA);
  366 
  367         /* Leave configuration mode. */
  368         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_EXIT);
  369         return retval;
  370 }
  371 
  372 void
  373 upc2_write_config(struct upc_softc *sc, int reg, int val)
  374 {
  375         bus_space_tag_t iot = sc->sc_iot;
  376         bus_space_handle_t ioh = sc->sc_ioh;
  377 
  378         /* Switch into configuration mode. */
  379         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  380         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  381 
  382         /* Write register. */
  383         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, reg);
  384         bus_space_write_1(iot, ioh, UPC2_PORT_CFGDATA, val);
  385 
  386         /* Leave configuration mode. */
  387         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_EXIT);
  388 }

Cache object: 2cb155c9039056372adafa107cf41fad


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