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/exca/exca.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-4-Clause AND BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2002-2005 M. Warner Losh <imp@FreeBSD.org>
    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  *
   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  * This software may be derived from NetBSD i82365.c and other files with
   27  * the following copyright:
   28  *
   29  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
   30  *
   31  * Redistribution and use in source and binary forms, with or without
   32  * modification, are permitted provided that the following conditions
   33  * are met:
   34  * 1. Redistributions of source code must retain the above copyright
   35  *    notice, this list of conditions and the following disclaimer.
   36  * 2. Redistributions in binary form must reproduce the above copyright
   37  *    notice, this list of conditions and the following disclaimer in the
   38  *    documentation and/or other materials provided with the distribution.
   39  * 3. All advertising materials mentioning features or use of this software
   40  *    must display the following acknowledgement:
   41  *      This product includes software developed by Marc Horowitz.
   42  * 4. The name of the author may not be used to endorse or promote products
   43  *    derived from this software without specific prior written permission.
   44  *
   45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   46  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   47  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   48  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   49  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   50  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   51  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   52  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   53  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   54  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   55  */
   56 
   57 #include <sys/cdefs.h>
   58 __FBSDID("$FreeBSD$");
   59 
   60 #include <sys/param.h>
   61 #include <sys/systm.h>
   62 #include <sys/condvar.h>
   63 #include <sys/errno.h>
   64 #include <sys/kernel.h>
   65 #include <sys/malloc.h>
   66 #include <sys/queue.h>
   67 #include <sys/module.h>
   68 #include <sys/lock.h>
   69 #include <sys/mutex.h>
   70 #include <sys/conf.h>
   71 
   72 #include <sys/bus.h>
   73 #include <machine/bus.h>
   74 #include <sys/rman.h>
   75 #include <machine/resource.h>
   76 
   77 #include <dev/pccard/pccardreg.h>
   78 #include <dev/pccard/pccardvar.h>
   79 
   80 #include <dev/exca/excareg.h>
   81 #include <dev/exca/excavar.h>
   82 
   83 #ifdef EXCA_DEBUG
   84 #define DEVPRINTF(dev, fmt, args...)    device_printf((dev), (fmt), ## args)
   85 #define DPRINTF(fmt, args...)           printf(fmt, ## args)
   86 #else
   87 #define DEVPRINTF(dev, fmt, args...)
   88 #define DPRINTF(fmt, args...)
   89 #endif
   90 
   91 static const char *chip_names[] = 
   92 {
   93         "CardBus socket",
   94         "Intel i82365SL-A/B or clone",
   95         "Intel i82365sl-DF step",
   96         "VLSI chip",
   97         "Cirrus Logic PD6710",
   98         "Cirrus logic PD6722",
   99         "Cirrus Logic PD6729",
  100         "Vadem 365",
  101         "Vadem 465",
  102         "Vadem 468",
  103         "Vadem 469",
  104         "Ricoh RF5C296",
  105         "Ricoh RF5C396",
  106         "IBM clone",
  107         "IBM KING PCMCIA Controller"
  108 };
  109 
  110 static exca_getb_fn exca_mem_getb;
  111 static exca_putb_fn exca_mem_putb;
  112 static exca_getb_fn exca_io_getb;
  113 static exca_putb_fn exca_io_putb;
  114 
  115 /* memory */
  116 
  117 #define EXCA_MEMINFO(NUM) {                                             \
  118         EXCA_SYSMEM_ADDR ## NUM ## _START_LSB,                          \
  119         EXCA_SYSMEM_ADDR ## NUM ## _START_MSB,                          \
  120         EXCA_SYSMEM_ADDR ## NUM ## _STOP_LSB,                           \
  121         EXCA_SYSMEM_ADDR ## NUM ## _STOP_MSB,                           \
  122         EXCA_SYSMEM_ADDR ## NUM ## _WIN,                                \
  123         EXCA_CARDMEM_ADDR ## NUM ## _LSB,                               \
  124         EXCA_CARDMEM_ADDR ## NUM ## _MSB,                               \
  125         EXCA_ADDRWIN_ENABLE_MEM ## NUM,                                 \
  126 }
  127 
  128 static struct mem_map_index_st {
  129         int     sysmem_start_lsb;
  130         int     sysmem_start_msb;
  131         int     sysmem_stop_lsb;
  132         int     sysmem_stop_msb;
  133         int     sysmem_win;
  134         int     cardmem_lsb;
  135         int     cardmem_msb;
  136         int     memenable;
  137 } mem_map_index[] = {
  138         EXCA_MEMINFO(0),
  139         EXCA_MEMINFO(1),
  140         EXCA_MEMINFO(2),
  141         EXCA_MEMINFO(3),
  142         EXCA_MEMINFO(4)
  143 };
  144 #undef  EXCA_MEMINFO
  145 
  146 static uint8_t
  147 exca_mem_getb(struct exca_softc *sc, int reg)
  148 {
  149         return (bus_space_read_1(sc->bst, sc->bsh, sc->offset + reg));
  150 }
  151 
  152 static void
  153 exca_mem_putb(struct exca_softc *sc, int reg, uint8_t val)
  154 {
  155         bus_space_write_1(sc->bst, sc->bsh, sc->offset + reg, val);
  156 }
  157 
  158 static uint8_t
  159 exca_io_getb(struct exca_softc *sc, int reg)
  160 {
  161         bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
  162         return (bus_space_read_1(sc->bst, sc->bsh, EXCA_REG_DATA));
  163 }
  164 
  165 static void
  166 exca_io_putb(struct exca_softc *sc, int reg, uint8_t val)
  167 {
  168         bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_INDEX, reg + sc->offset);
  169         bus_space_write_1(sc->bst, sc->bsh, EXCA_REG_DATA, val);
  170 }
  171 
  172 /*
  173  * Helper function.  This will map the requested memory slot.  We setup the
  174  * map before we call this function.  This is used to initially force the
  175  * mapping, as well as later restore the mapping after it has been destroyed
  176  * in some fashion (due to a power event typically).
  177  */
  178 static void
  179 exca_do_mem_map(struct exca_softc *sc, int win)
  180 {
  181         struct mem_map_index_st *map;
  182         struct pccard_mem_handle *mem;
  183         uint32_t offset;
  184         uint32_t mem16;
  185         uint32_t attrmem;
  186         
  187         map = &mem_map_index[win];
  188         mem = &sc->mem[win];
  189         mem16 = (mem->kind & PCCARD_MEM_16BIT) ? 
  190             EXCA_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT : 0;
  191         attrmem = (mem->kind & PCCARD_MEM_ATTR) ?
  192             EXCA_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0;
  193         offset = ((mem->cardaddr >> EXCA_CARDMEM_ADDRX_SHIFT) -
  194           (mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT)) & 0x3fff;
  195         exca_putb(sc, map->sysmem_start_lsb,
  196             mem->addr >> EXCA_SYSMEM_ADDRX_SHIFT);
  197         exca_putb(sc, map->sysmem_start_msb,
  198             ((mem->addr >> (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
  199             EXCA_SYSMEM_ADDRX_START_MSB_ADDR_MASK) | mem16);
  200 
  201         exca_putb(sc, map->sysmem_stop_lsb,
  202             (mem->addr + mem->realsize - 1) >> EXCA_SYSMEM_ADDRX_SHIFT);
  203         exca_putb(sc, map->sysmem_stop_msb,
  204             (((mem->addr + mem->realsize - 1) >>
  205             (EXCA_SYSMEM_ADDRX_SHIFT + 8)) &
  206             EXCA_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) |
  207             EXCA_SYSMEM_ADDRX_STOP_MSB_WAIT2);
  208         exca_putb(sc, map->sysmem_win, mem->addr >> EXCA_MEMREG_WIN_SHIFT);
  209 
  210         exca_putb(sc, map->cardmem_lsb, offset & 0xff);
  211         exca_putb(sc, map->cardmem_msb, ((offset >> 8) &
  212             EXCA_CARDMEM_ADDRX_MSB_ADDR_MASK) | attrmem);
  213 
  214         DPRINTF("%s %d-bit memory",
  215             mem->kind & PCCARD_MEM_ATTR ? "attribute" : "common",
  216             mem->kind & PCCARD_MEM_16BIT ? 16 : 8);
  217         exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->memenable |
  218             EXCA_ADDRWIN_ENABLE_MEMCS16);
  219 
  220         DELAY(100);
  221 #ifdef EXCA_DEBUG
  222         {
  223                 int r1, r2, r3, r4, r5, r6, r7;
  224                 r1 = exca_getb(sc, map->sysmem_start_msb);
  225                 r2 = exca_getb(sc, map->sysmem_start_lsb);
  226                 r3 = exca_getb(sc, map->sysmem_stop_msb);
  227                 r4 = exca_getb(sc, map->sysmem_stop_lsb);
  228                 r5 = exca_getb(sc, map->cardmem_msb);
  229                 r6 = exca_getb(sc, map->cardmem_lsb);
  230                 r7 = exca_getb(sc, map->sysmem_win);
  231                 printf("exca_do_mem_map win %d: %#02x%#02x %#02x%#02x "
  232                     "%#02x%#02x %#02x (%#08x+%#06x.%#06x*%#06x) flags %#x\n",
  233                     win, r1, r2, r3, r4, r5, r6, r7,
  234                     mem->addr, mem->size, mem->realsize,
  235                     mem->cardaddr, mem->kind);
  236         }
  237 #endif
  238 }
  239 
  240 /*
  241  * public interface to map a resource.  kind is the type of memory to
  242  * map (either common or attribute).  Memory created via this interface
  243  * starts out at card address 0.  Since the only way to set this is
  244  * to set it on a struct resource after it has been mapped, we're safe
  245  * in maping this assumption.  Note that resources can be remapped using
  246  * exca_do_mem_map so that's how the card address can be set later.
  247  */
  248 int
  249 exca_mem_map(struct exca_softc *sc, int kind, struct resource *res)
  250 {
  251         int win;
  252 
  253         for (win = 0; win < EXCA_MEM_WINS; win++) {
  254                 if ((sc->memalloc & (1 << win)) == 0) {
  255                         sc->memalloc |= (1 << win);
  256                         break;
  257                 }
  258         }
  259         if (win >= EXCA_MEM_WINS)
  260                 return (ENOSPC);
  261         if (sc->flags & EXCA_HAS_MEMREG_WIN) {
  262 #ifdef __LP64__
  263                 if (rman_get_start(res) >> (EXCA_MEMREG_WIN_SHIFT + 8) != 0) {
  264                         device_printf(sc->dev,
  265                             "Does not support mapping above 4GB.");
  266                         return (EINVAL);
  267                 }
  268 #endif
  269         } else {
  270                 if (rman_get_start(res) >> EXCA_MEMREG_WIN_SHIFT != 0) {
  271                         device_printf(sc->dev,
  272                             "Does not support mapping above 16M.");
  273                         return (EINVAL);
  274                 }
  275         }
  276 
  277         sc->mem[win].cardaddr = 0;
  278         sc->mem[win].memt = rman_get_bustag(res);
  279         sc->mem[win].memh = rman_get_bushandle(res);
  280         sc->mem[win].addr = rman_get_start(res);
  281         sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1;
  282         sc->mem[win].realsize = sc->mem[win].size + EXCA_MEM_PAGESIZE - 1;
  283         sc->mem[win].realsize = sc->mem[win].realsize -
  284             (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
  285         sc->mem[win].kind = kind;
  286         DPRINTF("exca_mem_map window %d bus %x+%x card addr %x\n",
  287             win, sc->mem[win].addr, sc->mem[win].size, sc->mem[win].cardaddr);
  288         exca_do_mem_map(sc, win);
  289 
  290         return (0);
  291 }
  292 
  293 /*
  294  * Private helper function.  This turns off a given memory map that is in
  295  * use.  We do this by just clearing the enable bit in the pcic.  If we needed
  296  * to make memory unmapping/mapping pairs faster, we would have to store
  297  * more state information about the pcic and then use that to intelligently
  298  * to the map/unmap.  However, since we don't do that sort of thing often
  299  * (generally just at configure time), it isn't a case worth optimizing.
  300  */
  301 static void
  302 exca_mem_unmap(struct exca_softc *sc, int window)
  303 {
  304         if (window < 0 || window >= EXCA_MEM_WINS)
  305                 panic("exca_mem_unmap: window out of range");
  306 
  307         exca_clrb(sc, EXCA_ADDRWIN_ENABLE, mem_map_index[window].memenable);
  308         sc->memalloc &= ~(1 << window);
  309 }
  310 
  311 /*
  312  * Find the map that we're using to hold the resource.  This works well
  313  * so long as the client drivers don't do silly things like map the same
  314  * area mutliple times, or map both common and attribute memory at the
  315  * same time.  This latter restriction is a bug.  We likely should just
  316  * store a pointer to the res in the mem[x] data structure.
  317  */
  318 static int
  319 exca_mem_findmap(struct exca_softc *sc, struct resource *res)
  320 {
  321         int win;
  322 
  323         for (win = 0; win < EXCA_MEM_WINS; win++) {
  324                 if (sc->mem[win].memt == rman_get_bustag(res) &&
  325                     sc->mem[win].addr == rman_get_start(res) &&
  326                     sc->mem[win].size == rman_get_size(res))
  327                         return (win);
  328         }
  329         return (-1);
  330 }
  331 
  332 /*
  333  * Set the memory flag.  This means that we are setting if the memory
  334  * is coming from attribute memory or from common memory on the card.
  335  * CIS entries are generally in attribute memory (although they can
  336  * reside in common memory).  Generally, this is the only use for attribute
  337  * memory.  However, some cards require their drivers to dance in both
  338  * common and/or attribute memory and this interface (and setting the
  339  * offset interface) exist for such cards.
  340  */
  341 int
  342 exca_mem_set_flags(struct exca_softc *sc, struct resource *res, uint32_t flags)
  343 {
  344         int win;
  345 
  346         win = exca_mem_findmap(sc, res);
  347         if (win < 0) {
  348                 device_printf(sc->dev,
  349                     "set_res_flags: specified resource not active\n");
  350                 return (ENOENT);
  351         }
  352 
  353         switch (flags)
  354         {
  355         case PCCARD_A_MEM_ATTR:
  356                 sc->mem[win].kind |= PCCARD_MEM_ATTR;
  357                 break;
  358         case PCCARD_A_MEM_COM:
  359                 sc->mem[win].kind &= ~PCCARD_MEM_ATTR;
  360                 break;
  361         case PCCARD_A_MEM_16BIT:
  362                 sc->mem[win].kind |= PCCARD_MEM_16BIT;
  363                 break;
  364         case PCCARD_A_MEM_8BIT:
  365                 sc->mem[win].kind &= ~PCCARD_MEM_16BIT;
  366                 break;
  367         }
  368         exca_do_mem_map(sc, win);
  369         return (0);
  370 }
  371 
  372 /*
  373  * Given a resource, go ahead and unmap it if we can find it in the
  374  * resrouce list that's used.
  375  */
  376 int
  377 exca_mem_unmap_res(struct exca_softc *sc, struct resource *res)
  378 {
  379         int win;
  380 
  381         win = exca_mem_findmap(sc, res);
  382         if (win < 0)
  383                 return (ENOENT);
  384         exca_mem_unmap(sc, win);
  385         return (0);
  386 }
  387         
  388 /*
  389  * Set the offset of the memory.  We use this for reading the CIS and
  390  * frobbing the pccard's pccard registers (CCR, etc).  Some drivers
  391  * need to access arbitrary attribute and common memory during their
  392  * initialization and operation.
  393  */
  394 int
  395 exca_mem_set_offset(struct exca_softc *sc, struct resource *res,
  396     uint32_t cardaddr, uint32_t *deltap)
  397 {
  398         int win;
  399         uint32_t delta;
  400 
  401         win = exca_mem_findmap(sc, res);
  402         if (win < 0) {
  403                 device_printf(sc->dev,
  404                     "set_memory_offset: specified resource not active\n");
  405                 return (ENOENT);
  406         }
  407         sc->mem[win].cardaddr = rounddown2(cardaddr, EXCA_MEM_PAGESIZE);
  408         delta = cardaddr % EXCA_MEM_PAGESIZE;
  409         if (deltap)
  410                 *deltap = delta;
  411         sc->mem[win].realsize = sc->mem[win].size + delta +
  412             EXCA_MEM_PAGESIZE - 1;
  413         sc->mem[win].realsize = sc->mem[win].realsize -
  414             (sc->mem[win].realsize % EXCA_MEM_PAGESIZE);
  415         exca_do_mem_map(sc, win);
  416         return (0);
  417 }
  418                         
  419 
  420 /* I/O */
  421 
  422 #define EXCA_IOINFO(NUM) {                                              \
  423         EXCA_IOADDR ## NUM ## _START_LSB,                               \
  424         EXCA_IOADDR ## NUM ## _START_MSB,                               \
  425         EXCA_IOADDR ## NUM ## _STOP_LSB,                                \
  426         EXCA_IOADDR ## NUM ## _STOP_MSB,                                \
  427         EXCA_ADDRWIN_ENABLE_IO ## NUM,                                  \
  428         EXCA_IOCTL_IO ## NUM ## _WAITSTATE                              \
  429         | EXCA_IOCTL_IO ## NUM ## _ZEROWAIT                             \
  430         | EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_MASK                       \
  431         | EXCA_IOCTL_IO ## NUM ## _DATASIZE_MASK,                       \
  432         {                                                               \
  433                 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_CARD,                \
  434                 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE             \
  435                 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_8BIT,               \
  436                 EXCA_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE             \
  437                 | EXCA_IOCTL_IO ## NUM ## _DATASIZE_16BIT,              \
  438         }                                                               \
  439 }
  440 
  441 static struct io_map_index_st {
  442         int     start_lsb;
  443         int     start_msb;
  444         int     stop_lsb;
  445         int     stop_msb;
  446         int     ioenable;
  447         int     ioctlmask;
  448         int     ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */
  449 } io_map_index[] = {
  450         EXCA_IOINFO(0),
  451         EXCA_IOINFO(1),
  452 };
  453 #undef  EXCA_IOINFO
  454 
  455 static void
  456 exca_do_io_map(struct exca_softc *sc, int win)
  457 {
  458         struct io_map_index_st *map;
  459 
  460         struct pccard_io_handle *io;
  461 
  462         map = &io_map_index[win];
  463         io = &sc->io[win];
  464         exca_putb(sc, map->start_lsb, io->addr & 0xff);
  465         exca_putb(sc, map->start_msb, (io->addr >> 8) & 0xff);
  466 
  467         exca_putb(sc, map->stop_lsb, (io->addr + io->size - 1) & 0xff);
  468         exca_putb(sc, map->stop_msb, ((io->addr + io->size - 1) >> 8) & 0xff);
  469 
  470         exca_clrb(sc, EXCA_IOCTL, map->ioctlmask);
  471         exca_setb(sc, EXCA_IOCTL, map->ioctlbits[io->width]);
  472 
  473         exca_setb(sc, EXCA_ADDRWIN_ENABLE, map->ioenable);
  474 #ifdef EXCA_DEBUG
  475         {
  476                 int r1, r2, r3, r4;
  477                 r1 = exca_getb(sc, map->start_msb);
  478                 r2 = exca_getb(sc, map->start_lsb);
  479                 r3 = exca_getb(sc, map->stop_msb);
  480                 r4 = exca_getb(sc, map->stop_lsb);
  481                 DPRINTF("exca_do_io_map window %d: %02x%02x %02x%02x "
  482                     "(%08x+%08x)\n", win, r1, r2, r3, r4,
  483                     io->addr, io->size);
  484         }
  485 #endif
  486 }
  487 
  488 int
  489 exca_io_map(struct exca_softc *sc, int width, struct resource *r)
  490 {
  491         int win;
  492 #ifdef EXCA_DEBUG
  493         static char *width_names[] = { "auto", "io8", "io16"};
  494 #endif
  495         for (win=0; win < EXCA_IO_WINS; win++) {
  496                 if ((sc->ioalloc & (1 << win)) == 0) {
  497                         sc->ioalloc |= (1 << win);
  498                         break;
  499                 }
  500         }
  501         if (win >= EXCA_IO_WINS)
  502                 return (ENOSPC);
  503 
  504         sc->io[win].iot = rman_get_bustag(r);
  505         sc->io[win].ioh = rman_get_bushandle(r);
  506         sc->io[win].addr = rman_get_start(r);
  507         sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1;
  508         sc->io[win].flags = 0;
  509         sc->io[win].width = width;
  510         DPRINTF("exca_io_map window %d %s port %x+%x\n",
  511             win, width_names[width], sc->io[win].addr,
  512             sc->io[win].size);
  513         exca_do_io_map(sc, win);
  514 
  515         return (0);
  516 }
  517 
  518 static void
  519 exca_io_unmap(struct exca_softc *sc, int window)
  520 {
  521         if (window >= EXCA_IO_WINS)
  522                 panic("exca_io_unmap: window out of range");
  523 
  524         exca_clrb(sc, EXCA_ADDRWIN_ENABLE, io_map_index[window].ioenable);
  525 
  526         sc->ioalloc &= ~(1 << window);
  527 
  528         sc->io[window].iot = 0;
  529         sc->io[window].ioh = 0;
  530         sc->io[window].addr = 0;
  531         sc->io[window].size = 0;
  532         sc->io[window].flags = 0;
  533         sc->io[window].width = 0;
  534 }
  535 
  536 static int
  537 exca_io_findmap(struct exca_softc *sc, struct resource *res)
  538 {
  539         int win;
  540 
  541         for (win = 0; win < EXCA_IO_WINS; win++) {
  542                 if (sc->io[win].iot == rman_get_bustag(res) &&
  543                     sc->io[win].addr == rman_get_start(res) &&
  544                     sc->io[win].size == rman_get_size(res))
  545                         return (win);
  546         }
  547         return (-1);
  548 }
  549 
  550 
  551 int
  552 exca_io_unmap_res(struct exca_softc *sc, struct resource *res)
  553 {
  554         int win;
  555 
  556         win = exca_io_findmap(sc, res);
  557         if (win < 0)
  558                 return (ENOENT);
  559         exca_io_unmap(sc, win);
  560         return (0);
  561 }
  562 
  563 /* Misc */
  564 
  565 /*
  566  * If interrupts are enabled, then we should be able to just wait for
  567  * an interrupt routine to wake us up.  Busy waiting shouldn't be
  568  * necessary.  Sadly, not all legacy ISA cards support an interrupt
  569  * for the busy state transitions, at least according to their datasheets, 
  570  * so we busy wait a while here..
  571  */
  572 static void
  573 exca_wait_ready(struct exca_softc *sc)
  574 {
  575         int i;
  576         DEVPRINTF(sc->dev, "exca_wait_ready: status 0x%02x\n",
  577             exca_getb(sc, EXCA_IF_STATUS));
  578         for (i = 0; i < 10000; i++) {
  579                 if (exca_getb(sc, EXCA_IF_STATUS) & EXCA_IF_STATUS_READY)
  580                         return;
  581                 DELAY(500);
  582         }
  583         device_printf(sc->dev, "ready never happened, status = %02x\n",
  584             exca_getb(sc, EXCA_IF_STATUS));
  585 }
  586 
  587 /*
  588  * Reset the card.  Ideally, we'd do a lot of this via interrupts.
  589  * However, many PC Cards will deassert the ready signal.  This means
  590  * that they are asserting an interrupt.  This makes it hard to 
  591  * do anything but a busy wait here.  One could argue that these
  592  * such cards are broken, or that the bridge that allows this sort
  593  * of interrupt through isn't quite what you'd want (and may be a standards
  594  * violation).  However, such arguing would leave a huge class of PC Cards
  595  * and bridges out of reach for use in the system.
  596  *
  597  * Maybe I should reevaluate the above based on the power bug I fixed
  598  * in OLDCARD.
  599  */
  600 void
  601 exca_reset(struct exca_softc *sc, device_t child)
  602 {
  603         int win;
  604 
  605         /* enable socket i/o */
  606         exca_setb(sc, EXCA_PWRCTL, EXCA_PWRCTL_OE);
  607 
  608         exca_putb(sc, EXCA_INTR, EXCA_INTR_ENABLE);
  609         /* hold reset for 30ms */
  610         DELAY(30*1000);
  611         /* clear the reset flag */
  612         exca_setb(sc, EXCA_INTR, EXCA_INTR_RESET);
  613         /* wait 20ms as per PC Card standard (r2.01) section 4.3.6 */
  614         DELAY(20*1000);
  615 
  616         exca_wait_ready(sc);
  617 
  618         /* disable all address windows */
  619         exca_putb(sc, EXCA_ADDRWIN_ENABLE, 0);
  620 
  621         exca_setb(sc, EXCA_INTR, EXCA_INTR_CARDTYPE_IO);
  622         DEVPRINTF(sc->dev, "card type is io\n");
  623 
  624         /* reinstall all the memory and io mappings */
  625         for (win = 0; win < EXCA_MEM_WINS; ++win)
  626                 if (sc->memalloc & (1 << win))
  627                         exca_do_mem_map(sc, win);
  628         for (win = 0; win < EXCA_IO_WINS; ++win)
  629                 if (sc->ioalloc & (1 << win))
  630                         exca_do_io_map(sc, win);
  631 }
  632 
  633 /*
  634  * Initialize the exca_softc data structure for the first time.
  635  */
  636 void
  637 exca_init(struct exca_softc *sc, device_t dev, 
  638     bus_space_tag_t bst, bus_space_handle_t bsh, uint32_t offset)
  639 {
  640         sc->dev = dev;
  641         sc->memalloc = 0;
  642         sc->ioalloc = 0;
  643         sc->bst = bst;
  644         sc->bsh = bsh;
  645         sc->offset = offset;
  646         sc->flags = 0;
  647         sc->getb = exca_mem_getb;
  648         sc->putb = exca_mem_putb;
  649         sc->pccarddev = device_add_child(dev, "pccard", -1);
  650         if (sc->pccarddev == NULL)
  651                 DEVPRINTF(brdev, "WARNING: cannot add pccard bus.\n");
  652         else if (device_probe_and_attach(sc->pccarddev) != 0)
  653                 DEVPRINTF(brdev, "WARNING: cannot attach pccard bus.\n");
  654 }
  655 
  656 /*
  657  * Is this socket valid?
  658  */
  659 static int
  660 exca_valid_slot(struct exca_softc *exca)
  661 {
  662         uint8_t c;
  663 
  664         /* Assume the worst */
  665         exca->chipset = EXCA_BOGUS;
  666 
  667         /*
  668          * see if there's a PCMCIA controller here
  669          * Intel PCMCIA controllers use 0x82 and 0x83
  670          * IBM clone chips use 0x88 and 0x89, apparently
  671          */
  672         c = exca_getb(exca, EXCA_IDENT);
  673         DEVPRINTF(exca->dev, "Ident is %x\n", c);
  674         if ((c & EXCA_IDENT_IFTYPE_MASK) != EXCA_IDENT_IFTYPE_MEM_AND_IO)
  675                 return (0);
  676         if ((c & EXCA_IDENT_ZERO) != 0)
  677                 return (0);
  678         switch (c & EXCA_IDENT_REV_MASK) {
  679         /*
  680          *      82365 or clones.
  681          */
  682         case EXCA_IDENT_REV_I82365SLR0:
  683         case EXCA_IDENT_REV_I82365SLR1:
  684                 exca->chipset = EXCA_I82365;
  685                 /*
  686                  * Check for Vadem chips by unlocking their extra
  687                  * registers and looking for valid ID.  Bit 3 in
  688                  * the ID register is normally 0, except when
  689                  * EXCA_VADEMREV is set.  Other bridges appear
  690                  * to ignore this frobbing.
  691                  */
  692                 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
  693                     EXCA_VADEM_COOKIE1);
  694                 bus_space_write_1(exca->bst, exca->bsh, EXCA_REG_INDEX,
  695                     EXCA_VADEM_COOKIE2);
  696                 exca_setb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
  697                 c = exca_getb(exca, EXCA_IDENT);
  698                 if (c & 0x08) {
  699                         switch (c & 7) {
  700                         case 1:
  701                                 exca->chipset = EXCA_VG365;
  702                                 break;
  703                         case 2:
  704                                 exca->chipset = EXCA_VG465;
  705                                 break;
  706                         case 3:
  707                                 exca->chipset = EXCA_VG468;
  708                                 break;
  709                         default:
  710                                 exca->chipset = EXCA_VG469;
  711                                 break;
  712                         }
  713                         exca_clrb(exca, EXCA_VADEM_VMISC, EXCA_VADEM_REV);
  714                         break;
  715                 }
  716                 /*
  717                  * Check for RICOH RF5C[23]96 PCMCIA Controller
  718                  */
  719                 c = exca_getb(exca, EXCA_RICOH_ID);
  720                 if (c == EXCA_RID_396) {
  721                         exca->chipset = EXCA_RF5C396;
  722                         break;
  723                 } else if (c == EXCA_RID_296) {
  724                         exca->chipset = EXCA_RF5C296;
  725                         break;
  726                 }
  727                 /*
  728                  *      Check for Cirrus logic chips.
  729                  */
  730                 exca_putb(exca, EXCA_CIRRUS_CHIP_INFO, 0);
  731                 c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
  732                 if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) ==
  733                     EXCA_CIRRUS_CHIP_INFO_CHIP_ID) {
  734                         c = exca_getb(exca, EXCA_CIRRUS_CHIP_INFO);
  735                         if ((c & EXCA_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
  736                                 if (c & EXCA_CIRRUS_CHIP_INFO_SLOTS)
  737                                         exca->chipset = EXCA_PD6722;
  738                                 else
  739                                         exca->chipset = EXCA_PD6710;
  740                                 break;
  741                         }
  742                 }
  743                 break;
  744 
  745         case EXCA_IDENT_REV_I82365SLDF:
  746                 /*
  747                  *      Intel i82365sl-DF step or maybe a vlsi 82c146
  748                  * we detected the vlsi case earlier, so if the controller
  749                  * isn't set, we know it is a i82365sl step D.
  750                  * XXXX Except we didn't -- this is a regression but VLSI
  751                  * controllers are super hard to find these days for testing.
  752                  */
  753                 exca->chipset = EXCA_I82365SL_DF;
  754                 break;
  755         case EXCA_IDENT_REV_IBM1:
  756         case EXCA_IDENT_REV_IBM2:
  757                 exca->chipset = EXCA_IBM;
  758                 break;
  759         case EXCA_IDENT_REV_IBM_KING:
  760                 exca->chipset = EXCA_IBM_KING;
  761                 break;
  762         default:
  763                 return (0);
  764         }
  765         return (1);
  766 }
  767 
  768 /*
  769  * Probe the expected slots.  We maybe should set the ID for each of these
  770  * slots too while we're at it.  But maybe that belongs to a separate
  771  * function.
  772  *
  773  * The caller must guarantee that at least EXCA_NSLOTS are present in exca.
  774  */
  775 int
  776 exca_probe_slots(device_t dev, struct exca_softc *exca, bus_space_tag_t iot,
  777     bus_space_handle_t ioh)
  778 {
  779         int err;
  780         int i;
  781 
  782         err = ENXIO;
  783         for (i = 0; i < EXCA_NSLOTS; i++)  {
  784                 exca_init(&exca[i], dev, iot, ioh, i * EXCA_SOCKET_SIZE);
  785                 exca->getb = exca_io_getb;
  786                 exca->putb = exca_io_putb;
  787                 if (exca_valid_slot(&exca[i])) {
  788                         device_set_desc(dev, chip_names[exca[i].chipset]);
  789                         err = 0;
  790                 }
  791         }
  792         return (err);
  793 }
  794 
  795 void
  796 exca_insert(struct exca_softc *exca)
  797 {
  798         if (device_is_attached(exca->pccarddev)) {
  799                 if (CARD_ATTACH_CARD(exca->pccarddev) != 0)
  800                         device_printf(exca->dev,
  801                             "PC Card card activation failed\n");
  802         } else {
  803                 device_printf(exca->dev,
  804                     "PC Card inserted, but no pccard bus.\n");
  805         }
  806 }
  807   
  808 
  809 void
  810 exca_removal(struct exca_softc *exca)
  811 {
  812         if (device_is_attached(exca->pccarddev))
  813                 CARD_DETACH_CARD(exca->pccarddev);
  814 }
  815 
  816 int
  817 exca_activate_resource(struct exca_softc *exca, device_t child, int type,
  818     int rid, struct resource *res)
  819 {
  820         int err;
  821 
  822         if (rman_get_flags(res) & RF_ACTIVE)
  823                 return (0);
  824         err = BUS_ACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
  825             type, rid, res);
  826         if (err)
  827                 return (err);
  828         switch (type) {
  829         case SYS_RES_IOPORT:
  830                 err = exca_io_map(exca, PCCARD_WIDTH_AUTO, res);
  831                 break;
  832         case SYS_RES_MEMORY:
  833                 err = exca_mem_map(exca, 0, res);
  834                 break;
  835         }
  836         if (err)
  837                 BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
  838                     type, rid, res);
  839         return (err);
  840 }
  841 
  842 int
  843 exca_deactivate_resource(struct exca_softc *exca, device_t child, int type,
  844     int rid, struct resource *res)
  845 {
  846         if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */
  847                 switch (type) {
  848                 case SYS_RES_IOPORT:
  849                         if (exca_io_unmap_res(exca, res))
  850                                 return (ENOENT);
  851                         break;
  852                 case SYS_RES_MEMORY:
  853                         if (exca_mem_unmap_res(exca, res))
  854                                 return (ENOENT);
  855                         break;
  856                 }
  857         }
  858         return (BUS_DEACTIVATE_RESOURCE(device_get_parent(exca->dev), child,
  859             type, rid, res));
  860 }
  861 
  862 #if 0
  863 static struct resource *
  864 exca_alloc_resource(struct exca_softc *sc, device_t child, int type, int *rid,
  865     u_long start, u_long end, u_long count, uint flags)
  866 {
  867         struct resource *res = NULL;
  868         int tmp;
  869 
  870         switch (type) {
  871         case SYS_RES_MEMORY:
  872                 if (start < cbb_start_mem)
  873                         start = cbb_start_mem;
  874                 if (end < start)
  875                         end = start;
  876                 flags = (flags & ~RF_ALIGNMENT_MASK) |
  877                     rman_make_alignment_flags(CBB_MEMALIGN);
  878                 break;
  879         case SYS_RES_IOPORT:
  880                 if (start < cbb_start_16_io)
  881                         start = cbb_start_16_io;
  882                 if (end < start)
  883                         end = start;
  884                 break;
  885         case SYS_RES_IRQ:
  886                 tmp = rman_get_start(sc->irq_res);
  887                 if (start > tmp || end < tmp || count != 1) {
  888                         device_printf(child, "requested interrupt %ld-%ld,"
  889                             "count = %ld not supported by cbb\n",
  890                             start, end, count);
  891                         return (NULL);
  892                 }
  893                 flags |= RF_SHAREABLE;
  894                 start = end = rman_get_start(sc->irq_res);
  895                 break;
  896         }
  897         res = BUS_ALLOC_RESOURCE(up, child, type, rid,
  898             start, end, count, flags & ~RF_ACTIVE);
  899         if (res == NULL)
  900                 return (NULL);
  901         cbb_insert_res(sc, res, type, *rid);
  902         if (flags & RF_ACTIVE) {
  903                 if (bus_activate_resource(child, type, *rid, res) != 0) {
  904                         bus_release_resource(child, type, *rid, res);
  905                         return (NULL);
  906                 }
  907         }
  908 
  909         return (res);
  910 }
  911 
  912 static int
  913 exca_release_resource(struct exca_softc *sc, device_t child, int type,
  914     int rid, struct resource *res)
  915 {
  916         int error;
  917 
  918         if (rman_get_flags(res) & RF_ACTIVE) {
  919                 error = bus_deactivate_resource(child, type, rid, res);
  920                 if (error != 0)
  921                         return (error);
  922         }
  923         cbb_remove_res(sc, res);
  924         return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
  925             type, rid, res));
  926 }
  927 #endif
  928 
  929 static int
  930 exca_modevent(module_t mod, int cmd, void *arg)
  931 {
  932         return 0;
  933 }
  934 
  935 DEV_MODULE(exca, exca_modevent, NULL);
  936 MODULE_VERSION(exca, 1);

Cache object: 48e95d97af159590a1072117a0ae811b


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