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.7 2003/11/29 19:33:34 bjh21 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.7 2003/11/29 19:33:34 bjh21 Exp $");
   43 
   44 #include <sys/param.h>
   45 #include <sys/device.h>
   46 #include <sys/systm.h>
   47 
   48 #include <machine/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 upc_submatch(struct device *, struct cfdata *, void *);
   74 static int upc2_com3_addr(int);
   75 static int upc2_com4_addr(int);
   76 
   77 void
   78 upc_attach(struct upc_softc *sc)
   79 {
   80 
   81         if (upc1_probe(sc))
   82                 upc1_attach(sc);
   83         else
   84                 upc2_attach(sc);
   85 }
   86 
   87 static int
   88 upc1_probe(struct upc_softc *sc)
   89 {
   90 
   91         return upc1_read_config(sc, UPC1_CFGADDR_CONFBASE) ==
   92             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT;
   93 }
   94 
   95 static void
   96 upc1_attach(struct upc_softc *sc)
   97 {
   98         u_int8_t cr[16];
   99         int i;
  100 
  101         aprint_normal(": 82C710\n");
  102         /* Dump configuration */
  103         for (i = 0; i < 16; i++)
  104                 cr[i] = upc1_read_config(sc, i);
  105 
  106         aprint_verbose("%s: config state", sc->sc_dev.dv_xname);
  107         for (i = 0; i < 16; i++)
  108                 aprint_verbose(" %02x", cr[i]);
  109         aprint_verbose("\n");
  110 
  111         /* FDC */
  112         if (cr[UPC1_CFGADDR_CRC] & UPC1_CRC_FDCEN)
  113                 upc_found(sc, "fdc", UPC_PORT_FDCBASE, 2, &sc->sc_fintr);
  114         /* IDE */
  115         if (cr[UPC1_CFGADDR_CRC] & UPC1_CRC_IDEEN)
  116                 upc_found2(sc, "wdc", UPC_PORT_IDECMDBASE, 8,
  117                            UPC_PORT_IDECTLBASE, 2, &sc->sc_wintr);
  118         /* Parallel */
  119         if (cr[UPC1_CFGADDR_CR0] & UPC1_CR0_PEN)
  120                 upc_found(sc, "lpt",
  121                     cr[UPC1_CFGADDR_PARBASE] << UPC1_PARBASE_SHIFT,
  122                     LPT_NPORTS, &sc->sc_pintr);
  123         /* UART */
  124         if (cr[UPC1_CFGADDR_CR0] & UPC1_CR0_SEN)
  125                 upc_found(sc, "com",
  126                     cr[UPC1_CFGADDR_UARTBASE] << UPC1_UARTBASE_SHIFT,
  127                     COM_NPORTS, &sc->sc_irq4);
  128         /* Mouse */
  129         /* XXX not yet supported */
  130 }
  131 
  132 static void
  133 upc2_attach(struct upc_softc *sc)
  134 {
  135         u_int8_t cr[5];
  136         int i;
  137 
  138         aprint_normal(": 82C711/82C721");
  139         /* Dump configuration */
  140         for (i = 0; i < 5; i++)
  141                 cr[i] = upc2_read_config(sc, i);
  142 
  143         aprint_verbose(", config state %02x %02x %02x %02x %02x",
  144                cr[0], cr[1], cr[2], cr[3], cr[4]);
  145         aprint_normal("\n");
  146 
  147         /* "Find" the attached devices */
  148         /* FDC */
  149         if (cr[0] & UPC2_CR0_FDC_ENABLE)
  150                 upc_found(sc, "fdc", UPC_PORT_FDCBASE, 2, &sc->sc_fintr);
  151         /* IDE */
  152         if (cr[0] & UPC2_CR0_IDE_ENABLE)
  153                 upc_found2(sc, "wdc", UPC_PORT_IDECMDBASE, 8,
  154                            UPC_PORT_IDECTLBASE, 2, &sc->sc_wintr);
  155         /* Parallel */
  156         switch (cr[1] & UPC2_CR1_LPT_MASK) {
  157         case UPC2_CR1_LPT_3BC:
  158                 upc_found(sc, "lpt", 0x3bc, LPT_NPORTS, &sc->sc_pintr);
  159                 break;
  160         case UPC2_CR1_LPT_378:
  161                 upc_found(sc, "lpt", 0x378, LPT_NPORTS, &sc->sc_pintr);
  162                 break;
  163         case UPC2_CR1_LPT_278:
  164                 upc_found(sc, "lpt", 0x278, LPT_NPORTS, &sc->sc_pintr);
  165                 break;
  166         }
  167         /* UART1 */
  168         if (cr[2] & UPC2_CR2_UART1_ENABLE) {
  169                 switch (cr[2] & UPC2_CR2_UART1_MASK) {
  170                 case UPC2_CR2_UART1_3F8:
  171                         upc_found(sc, "com", 0x3f8, COM_NPORTS, &sc->sc_irq4);
  172                         break;
  173                 case UPC2_CR2_UART1_2F8:
  174                         upc_found(sc, "com", 0x2f8, COM_NPORTS, &sc->sc_irq3);
  175                         break;
  176                 case UPC2_CR2_UART1_COM3:
  177                         upc_found(sc, "com", upc2_com3_addr(cr[1]), COM_NPORTS,
  178                                   &sc->sc_irq4);
  179                         break;
  180                 case UPC2_CR2_UART1_COM4:
  181                         upc_found(sc, "com", upc2_com4_addr(cr[1]), COM_NPORTS,
  182                                   &sc->sc_irq3);
  183                         break;
  184                 }
  185         }
  186         /* UART2 */
  187         if (cr[2] & UPC2_CR2_UART2_ENABLE) {
  188                 switch (cr[2] & UPC2_CR2_UART2_MASK) {
  189                 case UPC2_CR2_UART2_3F8:
  190                         upc_found(sc, "com", 0x3f8, COM_NPORTS, &sc->sc_irq4);
  191                         break;
  192                 case UPC2_CR2_UART2_2F8:
  193                         upc_found(sc, "com", 0x2f8, COM_NPORTS, &sc->sc_irq3);
  194                         break;
  195                 case UPC2_CR2_UART2_COM3:
  196                         upc_found(sc, "com", upc2_com3_addr(cr[1]), COM_NPORTS,
  197                                   &sc->sc_irq4);
  198                         break;
  199                 case UPC2_CR2_UART2_COM4:
  200                         upc_found(sc, "com", upc2_com4_addr(cr[1]), COM_NPORTS,
  201                                   &sc->sc_irq3);
  202                         break;
  203                 }
  204         }
  205 
  206 }
  207 
  208 static void
  209 upc_found(struct upc_softc *sc, char const *devtype, int offset, int size,
  210           struct upc_irqhandle *uih)
  211 {
  212         struct upc_attach_args ua;
  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         config_found_sm(&sc->sc_dev, &ua, upc_print, upc_submatch);
  220 }
  221 
  222 static void 
  223 upc_found2(struct upc_softc *sc, char const *devtype, int offset, int size,
  224            int offset2, int size2, struct upc_irqhandle *uih)
  225 {
  226         struct upc_attach_args ua;
  227 
  228         ua.ua_devtype = devtype;
  229         ua.ua_offset = offset;
  230         ua.ua_iot = sc->sc_iot;
  231         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset, size, &ua.ua_ioh);
  232         bus_space_subregion(sc->sc_iot, sc->sc_ioh, offset2, size2,
  233                             &ua.ua_ioh2);
  234         ua.ua_irqhandle = uih;
  235         config_found_sm(&sc->sc_dev, &ua, upc_print, upc_submatch);
  236 }
  237 
  238 void
  239 upc_intr_establish(struct upc_irqhandle *uih, int level, int (*func)(void *),
  240                    void *arg) {
  241 
  242         uih->uih_level = level;
  243         uih->uih_func = func;
  244         uih->uih_arg = arg;
  245         /* Actual MD establishment will be handled later by bus attachment. */
  246 }
  247 
  248 static int
  249 upc2_com3_addr(int cr1)
  250 {
  251 
  252         switch (cr1 & UPC2_CR1_COM34_MASK) {
  253         case UPC2_CR1_COM34_338_238:
  254                 return 0x338;
  255         case UPC2_CR1_COM34_3E8_2E8:
  256                 return 0x3e8;
  257         case UPC2_CR1_COM34_2E8_2E0:
  258                 return 0x2e8;
  259         case UPC2_CR1_COM34_220_228:
  260                 return 0x220;
  261         }
  262         return -1;
  263 }
  264 
  265 static int
  266 upc2_com4_addr(int cr1)
  267 {
  268 
  269         switch (cr1 & UPC2_CR1_COM34_MASK) {
  270         case UPC2_CR1_COM34_338_238:
  271                 return 0x238;
  272         case UPC2_CR1_COM34_3E8_2E8:
  273                 return 0x2e8;
  274         case UPC2_CR1_COM34_2E8_2E0:
  275                 return 0x2e0;
  276         case UPC2_CR1_COM34_220_228:
  277                 return 0x228;
  278         }
  279         return -1;
  280 }
  281 
  282 static int
  283 upc_print(void *aux, char const *pnp)
  284 {
  285         struct upc_attach_args *ua = aux;
  286 
  287         if (pnp)
  288                 aprint_normal("%s at %s", ua->ua_devtype, pnp);
  289         aprint_normal(" offset 0x%x", ua->ua_offset);
  290         return UNCONF;
  291 }
  292 
  293 static int
  294 upc_submatch(struct device *parent, struct cfdata *cf, void *aux)
  295 {
  296         struct upc_attach_args *ua = aux;
  297 
  298         if (strcmp(cf->cf_name, ua->ua_devtype) == 0 &&
  299             (cf->cf_loc[UPCCF_OFFSET] == UPCCF_OFFSET_DEFAULT ||
  300              cf->cf_loc[UPCCF_OFFSET] == ua->ua_offset))
  301                 return config_match(parent, cf, aux);
  302         return 0;
  303 }
  304 
  305 int
  306 upc1_read_config(struct upc_softc *sc, int reg)
  307 {
  308         bus_space_tag_t iot = sc->sc_iot;
  309         bus_space_handle_t ioh = sc->sc_ioh;
  310         int retval;
  311 
  312         /* Switch into configuration mode. */
  313         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1, UPC1_CFGMAGIC_1);
  314         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_2);
  315         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_3);
  316         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2,
  317             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT);
  318         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1,
  319             (UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT) ^ 0xff);
  320 
  321         /* Read register. */
  322         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, reg);
  323         retval = bus_space_read_1(iot, ioh, UPC1_PORT_CAP);
  324 
  325         /* Leave configuration mode. */
  326         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, UPC1_CFGADDR_EXIT);
  327         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, 0);
  328         return retval;
  329 }
  330 
  331 void
  332 upc1_write_config(struct upc_softc *sc, int reg, int val)
  333 {
  334         bus_space_tag_t iot = sc->sc_iot;
  335         bus_space_handle_t ioh = sc->sc_ioh;
  336 
  337         /* Switch into configuration mode. */
  338         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1, UPC1_CFGMAGIC_1);
  339         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_2);
  340         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2, UPC1_CFGMAGIC_3);
  341         bus_space_write_1(iot, ioh, UPC1_PORT_CFG2,
  342             UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT);
  343         bus_space_write_1(iot, ioh, UPC1_PORT_CFG1,
  344             (UPC1_PORT_CRI >> UPC1_CONFBASE_SHIFT) ^ 0xff);
  345 
  346         /* Read register. */
  347         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, reg);
  348         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, val);
  349 
  350         /* Leave configuration mode. */
  351         bus_space_write_1(iot, ioh, UPC1_PORT_CRI, UPC1_CFGADDR_EXIT);
  352         bus_space_write_1(iot, ioh, UPC1_PORT_CAP, 0);
  353 }
  354 
  355 int
  356 upc2_read_config(struct upc_softc *sc, int reg)
  357 {
  358         bus_space_tag_t iot = sc->sc_iot;
  359         bus_space_handle_t ioh = sc->sc_ioh;
  360         int retval;
  361 
  362         /* Switch into configuration mode. */
  363         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  364         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  365 
  366         /* Read register. */
  367         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, reg);
  368         retval = bus_space_read_1(iot, ioh, UPC2_PORT_CFGDATA);
  369 
  370         /* Leave configuration mode. */
  371         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_EXIT);
  372         return retval;
  373 }
  374 
  375 void
  376 upc2_write_config(struct upc_softc *sc, int reg, int val)
  377 {
  378         bus_space_tag_t iot = sc->sc_iot;
  379         bus_space_handle_t ioh = sc->sc_ioh;
  380 
  381         /* Switch into configuration mode. */
  382         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  383         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_ENTER);
  384 
  385         /* Write register. */
  386         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, reg);
  387         bus_space_write_1(iot, ioh, UPC2_PORT_CFGDATA, val);
  388 
  389         /* Leave configuration mode. */
  390         bus_space_write_1(iot, ioh, UPC2_PORT_CFGADDR, UPC2_CFGMAGIC_EXIT);
  391 }

Cache object: 70e53d0175f28d03fab18b9574a348fd


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