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

Cache object: d0a0cc9b30b14acdb4927dac8709be34


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