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

Cache object: a984ef84665e2ae2b15eded2089b3e60


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