The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/sti.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: sti.c,v 1.31 2021/08/07 16:19:12 thorpej Exp $ */
    2 
    3 /*      $OpenBSD: sti.c,v 1.61 2009/09/05 14:09:35 miod Exp $   */
    4 
    5 /*
    6  * Copyright (c) 2000-2003 Michael Shalayeff
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
   22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   24  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   28  * THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 /*
   31  * TODO:
   32  *      call sti procs asynchronously;
   33  *      implement console scroll-back;
   34  *      X11 support on more models.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: sti.c,v 1.31 2021/08/07 16:19:12 thorpej Exp $");
   39 
   40 #include "wsdisplay.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/device.h>
   45 #include <sys/malloc.h>
   46 
   47 #include <uvm/uvm_extern.h>
   48 
   49 #include <sys/bus.h>
   50 
   51 #include <dev/wscons/wsdisplayvar.h>
   52 #include <dev/wscons/wsconsio.h>
   53 
   54 #include <dev/ic/stireg.h>
   55 #include <dev/ic/stivar.h>
   56 
   57 #ifdef STIDEBUG
   58 
   59 #define DPRINTF(s)      do {    \
   60         if (stidebug)           \
   61                 printf s;       \
   62 } while(0)
   63 
   64 int stidebug = 1;
   65 #else
   66 #define DPRINTF(s)      /* */
   67 #endif
   68 
   69 void sti_cursor(void *, int, int, int);
   70 int  sti_mapchar(void *, int, u_int *);
   71 void sti_putchar(void *, int, int, u_int, long);
   72 void sti_copycols(void *, int, int, int, int);
   73 void sti_erasecols(void *, int, int, int, long);
   74 void sti_copyrows(void *, int, int, int);
   75 void sti_eraserows(void *, int, int, long);
   76 int  sti_alloc_attr(void *, int, int, int, long *);
   77 
   78 /* pseudo attribute ops for sti ROM putchar function */
   79 #define WSATTR_FG_SHIFT 24
   80 #define WSATTR_BG_SHIFT 16
   81 #define WSATTR_UNPACK_FG(attr)  (((attr) >> WSATTR_FG_SHIFT) & 0xff)
   82 #define WSATTR_UNPACK_BG(attr)  (((attr) >> WSATTR_BG_SHIFT) & 0xff)
   83 #define WSATTR_UNPACK_FLAG(attr) ((attr) & WSATTR_USERMASK)
   84 #define WSATTR_PACK_FG(fg)      ((fg) << WSATTR_FG_SHIFT)
   85 #define WSATTR_PACK_BG(bg)      ((bg) << WSATTR_BG_SHIFT)
   86 #define WSATTR_PACK_FLAG(flag)  ((flag))
   87 #define WSATTR_PACK(fg, bg, flag)       \
   88     (WSATTR_PACK_FG(fg) | WSATTR_PACK_BG(bg) | WSATTR_PACK_FLAG(flag))
   89 
   90 struct wsdisplay_emulops sti_emulops = {
   91         .cursor = sti_cursor,
   92         .mapchar = sti_mapchar,
   93         .putchar = sti_putchar,
   94         .copycols = sti_copycols,
   95         .erasecols = sti_erasecols,
   96         .copyrows = sti_copyrows,
   97         .eraserows = sti_eraserows,
   98         .allocattr = sti_alloc_attr
   99 };
  100 
  101 const struct wsdisplay_accessops sti_accessops = {
  102         .ioctl = sti_ioctl,
  103         .mmap = sti_mmap,
  104         .alloc_screen = sti_alloc_screen,
  105         .free_screen = sti_free_screen,
  106         .show_screen = sti_show_screen,
  107         .load_font = sti_load_font
  108 };
  109 
  110 enum sti_bmove_funcs {
  111         bmf_clear, bmf_copy, bmf_invert, bmf_underline
  112 };
  113 
  114 void    sti_bmove(struct sti_screen *, int, int, int, int, int, int,
  115             enum sti_bmove_funcs);
  116 int     sti_inqcfg(struct sti_screen *, struct sti_inqconfout *);
  117 int     sti_setcment(struct sti_screen *, u_int, u_char, u_char, u_char);
  118 
  119 struct sti_screen *sti_attach_screen(struct sti_softc *, int);
  120 void    sti_describe_screen(struct sti_softc *, struct sti_screen *);
  121 
  122 int     sti_fetchfonts(struct sti_screen *, struct sti_inqconfout *, uint32_t,
  123             u_int);
  124 void    sti_region_setup(struct sti_screen *);
  125 int     sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
  126             bus_space_handle_t, bus_addr_t *, u_int);
  127 int     sti_screen_setup(struct sti_screen *, int);
  128 
  129 int     ngle_default_putcmap(struct sti_screen *, u_int, u_int);
  130 
  131 #ifndef SMALL_KERNEL
  132 void    ngle_artist_setupfb(struct sti_screen *);
  133 void    ngle_elk_setupfb(struct sti_screen *);
  134 void    ngle_timber_setupfb(struct sti_screen *);
  135 int     ngle_putcmap(struct sti_screen *, u_int, u_int);
  136 #endif
  137 
  138 #define STI_ENABLE_ROM(sc) \
  139 do { \
  140         if ((sc) != NULL && (sc)->sc_enable_rom != NULL) \
  141                 (*(sc)->sc_enable_rom)(sc); \
  142 } while (0)
  143 #define STI_DISABLE_ROM(sc) \
  144 do { \
  145         if ((sc) != NULL && (sc)->sc_disable_rom != NULL) \
  146                 (*(sc)->sc_disable_rom)(sc); \
  147 } while (0)
  148 
  149 /* Macros to read larger than 8 bit values from byte roms */
  150 #define parseshort(o) \
  151         ((bus_space_read_1(memt, romh, (o) + 3) <<  8) | \
  152          (bus_space_read_1(memt, romh, (o) + 7)))
  153 #define parseword(o) \
  154         ((bus_space_read_1(memt, romh, (o) +  3) << 24) | \
  155          (bus_space_read_1(memt, romh, (o) +  7) << 16) | \
  156          (bus_space_read_1(memt, romh, (o) + 11) <<  8) | \
  157          (bus_space_read_1(memt, romh, (o) + 15)))
  158 
  159 int
  160 sti_attach_common(struct sti_softc *sc, bus_space_tag_t iot,
  161     bus_space_tag_t memt, bus_space_handle_t romh, u_int codebase)
  162 {
  163         struct sti_rom *rom;
  164         int rc;
  165 
  166         rom = (struct sti_rom *)malloc(sizeof(*rom), M_DEVBUF,
  167             M_WAITOK | M_ZERO);
  168         rom->rom_softc = sc;
  169         rc = sti_rom_setup(rom, iot, memt, romh, sc->bases, codebase);
  170         if (rc != 0) {
  171                 free(rom, M_DEVBUF);
  172                 return rc;
  173         }
  174 
  175         sc->sc_rom = rom;
  176 
  177         sti_describe(sc);
  178 
  179         sc->sc_scr = sti_attach_screen(sc,
  180             sc->sc_flags & STI_CONSOLE ? 0 : STI_CLEARSCR);
  181         if (sc->sc_scr == NULL)
  182                 rc = ENOMEM;
  183 
  184         return rc;
  185 }
  186 
  187 struct sti_screen *
  188 sti_attach_screen(struct sti_softc *sc, int flags)
  189 {
  190         struct sti_screen *scr;
  191         int rc;
  192 
  193         scr = (struct sti_screen *)malloc(sizeof(*scr), M_DEVBUF,
  194             M_WAITOK | M_ZERO);
  195         scr->scr_rom = sc->sc_rom;
  196         rc = sti_screen_setup(scr, flags);
  197         if (rc != 0) {
  198                 free(scr, M_DEVBUF);
  199                 return NULL;
  200         }
  201 
  202         sti_describe_screen(sc, scr);
  203 
  204         return scr;
  205 }
  206 
  207 int
  208 sti_rom_setup(struct sti_rom *rom, bus_space_tag_t iot, bus_space_tag_t memt,
  209     bus_space_handle_t romh, bus_addr_t *bases, u_int codebase)
  210 {
  211         struct sti_dd *dd;
  212         int error, size, i;
  213 
  214         KASSERT(rom != NULL);
  215         STI_ENABLE_ROM(rom->rom_softc);
  216 
  217         rom->iot = iot;
  218         rom->memt = memt;
  219         rom->romh = romh;
  220         rom->bases = bases;
  221 
  222         /*
  223          * Get ROM header and code function pointers.
  224          */
  225 
  226         dd = &rom->rom_dd;
  227         rom->rom_devtype = bus_space_read_1(memt, romh, 3);
  228         if (rom->rom_devtype == STI_DEVTYPE1) {
  229                 dd->dd_type      = bus_space_read_1(memt, romh, 0x03);
  230                 dd->dd_nmon      = bus_space_read_1(memt, romh, 0x07);
  231                 dd->dd_grrev     = bus_space_read_1(memt, romh, 0x0b);
  232                 dd->dd_lrrev     = bus_space_read_1(memt, romh, 0x0f);
  233                 dd->dd_grid[0]   = parseword(0x10);
  234                 dd->dd_grid[1]   = parseword(0x20);
  235                 dd->dd_fntaddr   = parseword(0x30) & ~3;
  236                 dd->dd_maxst     = parseword(0x40);
  237                 dd->dd_romend    = parseword(0x50) & ~3;
  238                 dd->dd_reglst    = parseword(0x60) & ~3;
  239                 dd->dd_maxreent  = parseshort(0x70);
  240                 dd->dd_maxtimo   = parseshort(0x78);
  241                 dd->dd_montbl    = parseword(0x80) & ~3;
  242                 dd->dd_udaddr    = parseword(0x90) & ~3;
  243                 dd->dd_stimemreq = parseword(0xa0);
  244                 dd->dd_udsize    = parseword(0xb0);
  245                 dd->dd_pwruse    = parseshort(0xc0);
  246                 dd->dd_bussup    = bus_space_read_1(memt, romh, 0xcb);
  247                 dd->dd_ebussup   = bus_space_read_1(memt, romh, 0xcf);
  248                 dd->dd_altcodet  = bus_space_read_1(memt, romh, 0xd3);
  249                 dd->dd_eddst[0]  = bus_space_read_1(memt, romh, 0xd7);
  250                 dd->dd_eddst[1]  = bus_space_read_1(memt, romh, 0xdb);
  251                 dd->dd_eddst[2]  = bus_space_read_1(memt, romh, 0xdf);
  252                 dd->dd_cfbaddr   = parseword(0xe0) & ~3;
  253 
  254                 codebase <<= 2;
  255                 dd->dd_pacode[0x0] = parseword(codebase + 0x000) & ~3;
  256                 dd->dd_pacode[0x1] = parseword(codebase + 0x010) & ~3;
  257                 dd->dd_pacode[0x2] = parseword(codebase + 0x020) & ~3;
  258                 dd->dd_pacode[0x3] = parseword(codebase + 0x030) & ~3;
  259                 dd->dd_pacode[0x4] = parseword(codebase + 0x040) & ~3;
  260                 dd->dd_pacode[0x5] = parseword(codebase + 0x050) & ~3;
  261                 dd->dd_pacode[0x6] = parseword(codebase + 0x060) & ~3;
  262                 dd->dd_pacode[0x7] = parseword(codebase + 0x070) & ~3;
  263                 dd->dd_pacode[0x8] = parseword(codebase + 0x080) & ~3;
  264                 dd->dd_pacode[0x9] = parseword(codebase + 0x090) & ~3;
  265                 dd->dd_pacode[0xa] = parseword(codebase + 0x0a0) & ~3;
  266                 dd->dd_pacode[0xb] = parseword(codebase + 0x0b0) & ~3;
  267                 dd->dd_pacode[0xc] = parseword(codebase + 0x0c0) & ~3;
  268                 dd->dd_pacode[0xd] = parseword(codebase + 0x0d0) & ~3;
  269                 dd->dd_pacode[0xe] = parseword(codebase + 0x0e0) & ~3;
  270                 dd->dd_pacode[0xf] = parseword(codebase + 0x0f0) & ~3;
  271         } else {        /* STI_DEVTYPE4 */
  272                 bus_space_read_region_stream_4(memt, romh, 0, (uint32_t *)dd,
  273                     sizeof(*dd) / 4);
  274                 /* fix pacode... */
  275                 bus_space_read_region_stream_4(memt, romh, codebase,
  276                     (uint32_t *)dd->dd_pacode, sizeof(dd->dd_pacode) / 4);
  277         }
  278 
  279         STI_DISABLE_ROM(rom->rom_softc);
  280 
  281         DPRINTF(("dd:\n"
  282             "devtype=%x, rev=%x;%d, altt=%x, gid=%08x%08x, font=%x, mss=%x\n"
  283             "end=%x, regions=%x, msto=%x, timo=%d, mont=%x, user=%x[%x]\n"
  284             "memrq=%x, pwr=%d, bus=%x, ebus=%x, cfb=%x\n"
  285             "code=",
  286             dd->dd_type & 0xff, dd->dd_grrev, dd->dd_lrrev, dd->dd_altcodet,
  287             dd->dd_grid[0], dd->dd_grid[1], dd->dd_fntaddr, dd->dd_maxst,
  288             dd->dd_romend, dd->dd_reglst, dd->dd_maxreent, dd->dd_maxtimo,
  289             dd->dd_montbl, dd->dd_udaddr, dd->dd_udsize, dd->dd_stimemreq,
  290             dd->dd_pwruse, dd->dd_bussup, dd->dd_ebussup, dd->dd_cfbaddr));
  291         DPRINTF(("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
  292             dd->dd_pacode[0x0], dd->dd_pacode[0x1], dd->dd_pacode[0x2],
  293             dd->dd_pacode[0x3], dd->dd_pacode[0x4], dd->dd_pacode[0x5],
  294             dd->dd_pacode[0x6], dd->dd_pacode[0x7], dd->dd_pacode[0x8],
  295             dd->dd_pacode[0x9], dd->dd_pacode[0xa], dd->dd_pacode[0xb],
  296             dd->dd_pacode[0xc], dd->dd_pacode[0xd], dd->dd_pacode[0xe],
  297             dd->dd_pacode[0xf]));
  298 
  299         /*
  300          * Figure out how many bytes we need for the STI code.
  301          * Note there could be fewer than STI_END pointer entries
  302          * populated, especially on older devices.
  303          */
  304         for (i = STI_END; dd->dd_pacode[i] == 0; i--)
  305                 ;
  306 
  307         size = dd->dd_pacode[i] - dd->dd_pacode[STI_BEGIN];
  308 
  309         if (rom->rom_devtype == STI_DEVTYPE1)
  310                 size = (size + 3) / 4;
  311         if (size == 0) {
  312                 aprint_error(": no code for the requested platform\n");
  313                 return EINVAL;
  314         }
  315 
  316         if (!(rom->rom_code = uvm_km_alloc(kernel_map, round_page(size), 0,
  317             UVM_KMF_WIRED))) {
  318                 aprint_error(": cannot allocate %u bytes for code\n", size);
  319                 return ENOMEM;
  320         }
  321         DPRINTF(("code=0x%lx[%x]\n", rom->rom_code, size));
  322 
  323         /*
  324          * Copy code into memory and make it executable.
  325          */
  326 
  327         STI_ENABLE_ROM(rom->rom_softc);
  328 
  329         if (rom->rom_devtype == STI_DEVTYPE1) {
  330                 uint8_t *p;
  331                 uint32_t addr, eaddr;
  332 
  333                 p = (uint8_t *)rom->rom_code;
  334 
  335                 for (addr = dd->dd_pacode[STI_BEGIN], eaddr = addr + size * 4;
  336                     addr < eaddr; addr += 4 ) {
  337                         *p++ = bus_space_read_4(memt, romh, addr) & 0xff;
  338                 }
  339         } else {        /* STI_DEVTYPE4 */
  340                 bus_space_read_region_stream_4(memt, romh,
  341                     dd->dd_pacode[STI_BEGIN], (uint32_t *)rom->rom_code,
  342                     size / 4);
  343         }
  344 
  345         STI_DISABLE_ROM(rom->rom_softc);
  346 
  347         if ((error = uvm_map_protect(kernel_map, rom->rom_code,
  348             rom->rom_code + round_page(size), UVM_PROT_RX, FALSE))) {
  349                 aprint_error(": uvm_map_protect failed (%d)\n", error);
  350                 uvm_km_free(kernel_map, rom->rom_code, round_page(size),
  351                     UVM_KMF_WIRED);
  352                 return error;
  353         }
  354 
  355         /*
  356          * Setup code function pointers.
  357          */
  358 
  359 #define O(i) \
  360         (dd->dd_pacode[(i)] == 0 ? 0 : \
  361             (rom->rom_code + (dd->dd_pacode[(i)] - dd->dd_pacode[0]) /  \
  362             (rom->rom_devtype == STI_DEVTYPE1 ? 4 : 1)))
  363 
  364         rom->init       = (sti_init_t)O(STI_INIT_GRAPH);
  365         rom->mgmt       = (sti_mgmt_t)O(STI_STATE_MGMT);
  366         rom->unpmv      = (sti_unpmv_t)O(STI_FONT_UNPMV);
  367         rom->blkmv      = (sti_blkmv_t)O(STI_BLOCK_MOVE);
  368         rom->test       = (sti_test_t)O(STI_SELF_TEST);
  369         rom->exhdl      = (sti_exhdl_t)O(STI_EXCEP_HDLR);
  370         rom->inqconf    = (sti_inqconf_t)O(STI_INQ_CONF);
  371         rom->scment     = (sti_scment_t)O(STI_SCM_ENT);
  372         rom->dmac       = (sti_dmac_t)O(STI_DMA_CTRL);
  373         rom->flowc      = (sti_flowc_t)O(STI_FLOW_CTRL);
  374         rom->utiming    = (sti_utiming_t)O(STI_UTIMING);
  375         rom->pmgr       = (sti_pmgr_t)O(STI_PROC_MGR);
  376         rom->util       = (sti_util_t)O(STI_UTIL);
  377 
  378 #undef O
  379 
  380         /*
  381          * Set colormap entry is not implemented until 8.04, so force
  382          * a NULL pointer here.
  383          */
  384         if (dd->dd_grrev < STI_REVISION(8, 4)) {
  385                 rom->scment = NULL;
  386         }
  387 
  388         return 0;
  389 }
  390 
  391 /*
  392  * Map all regions.
  393  */
  394 void
  395 sti_region_setup(struct sti_screen *scr)
  396 {
  397         struct sti_rom *rom = scr->scr_rom;
  398         bus_space_tag_t memt = rom->memt;
  399         bus_space_handle_t romh = rom->romh;
  400         bus_addr_t *bases = rom->bases;
  401         struct sti_dd *dd = &rom->rom_dd;
  402         struct sti_cfg *cc = &scr->scr_cfg;
  403         struct sti_region regions[STI_REGION_MAX], *r;
  404         u_int regno, regcnt;
  405         bus_addr_t addr;
  406 
  407         DPRINTF(("stiregions @ %x:\n", dd->dd_reglst));
  408 
  409         /*
  410          * Read the region information.
  411          */
  412 
  413         STI_ENABLE_ROM(rom->rom_softc);
  414 
  415         if (rom->rom_devtype == STI_DEVTYPE1) {
  416                 for (regno = 0; regno < STI_REGION_MAX; regno++)
  417                         *(u_int *)(regions + regno) =
  418                             parseword(dd->dd_reglst + regno * 0x10);
  419         } else {
  420                 bus_space_read_region_stream_4(memt, romh, dd->dd_reglst,
  421                     (uint32_t *)regions, sizeof(regions) / 4);
  422         }
  423 
  424         STI_DISABLE_ROM(rom->rom_softc);
  425 
  426         /*
  427          * Count them.
  428          */
  429 
  430         for (regcnt = 0, r = regions; regcnt < STI_REGION_MAX; regcnt++, r++)
  431                 if (r->last)
  432                         break;
  433         regcnt++;
  434 
  435         /*
  436          * Map them.
  437          */
  438 
  439         for (regno = 0, r = regions; regno < regcnt; regno++, r++) {
  440                 if (r->length == 0)
  441                         continue;
  442 
  443                 /*
  444                  * Assume an existing mapping exists.
  445                  */
  446                 addr = bases[regno] + (r->offset << PGSHIFT);
  447                 DPRINTF(("%08x @ 0x%08x%s%s%s%s",
  448                     r->length << PGSHIFT, (int)addr, r->sys_only ? " sys" : "",
  449                     r->cache ? " cache" : "", r->btlb ? " btlb" : "",
  450                     r->last ? " last" : ""));
  451 
  452                 /*
  453                  * Region #0 is always the rom, and it should have been
  454                  * mapped already.
  455                  * XXX This expects a 1:1 mapping...
  456                  */
  457                 if (regno == 0 && romh == bases[0]) {
  458                         cc->regions[0] = addr;
  459                         DPRINTF(("\n"));
  460                         continue;
  461                 }
  462 
  463                 if (bus_space_map(memt, addr, r->length << PGSHIFT,
  464                     BUS_SPACE_MAP_LINEAR | (r->cache ?
  465                     BUS_SPACE_MAP_CACHEABLE : 0), &rom->regh[regno]) != 0) {
  466                         rom->regh[regno] = romh;        /* XXX */
  467                         DPRINTF((" - already mapped region\n"));
  468                 } else {
  469                         addr = (bus_addr_t)
  470                             bus_space_vaddr(memt, rom->regh[regno]);
  471                         if (regno == 1) {
  472                                 DPRINTF((" - fb"));
  473                                 scr->fbaddr = addr;
  474                                 scr->fblen = r->length << PGSHIFT;
  475                         }
  476                         DPRINTF(("\n"));
  477                 }
  478 
  479                 cc->regions[regno] = addr;
  480         }
  481 
  482 #ifdef STIDEBUG
  483         /*
  484          * Make sure we'll trap accessing unmapped regions
  485          */
  486         for (regno = 0; regno < STI_REGION_MAX; regno++)
  487                 if (cc->regions[regno] == 0)
  488                     cc->regions[regno] = 0x81234567;
  489 #endif
  490 }
  491 
  492 int
  493 sti_screen_setup(struct sti_screen *scr, int flags)
  494 {
  495         struct sti_rom *rom = scr->scr_rom;
  496         bus_space_tag_t memt = rom->memt;
  497         bus_space_handle_t romh = rom->romh;
  498         struct sti_dd *dd = &rom->rom_dd;
  499         struct sti_cfg *cc = &scr->scr_cfg;
  500         struct sti_inqconfout cfg;
  501         struct sti_einqconfout ecfg;
  502 #ifdef STIDEBUG
  503         char buf[256];
  504 #endif
  505         int error, i;
  506         int geometry_kluge = 0;
  507         u_int fontindex = 0;
  508 
  509         KASSERT(scr != NULL);
  510         memset(cc, 0, sizeof(*cc));
  511         cc->ext_cfg = &scr->scr_ecfg;
  512         memset(cc->ext_cfg, 0, sizeof(*cc->ext_cfg));
  513 
  514         if (dd->dd_stimemreq) {
  515                 scr->scr_ecfg.addr =
  516                     malloc(dd->dd_stimemreq, M_DEVBUF, M_WAITOK);
  517         }
  518 
  519         sti_region_setup(scr);
  520 
  521         if ((error = sti_init(scr, 0))) {
  522                 aprint_error(": cannot initialize (%d)\n", error);
  523                 goto fail;
  524         }
  525 
  526         memset(&cfg, 0, sizeof(cfg));
  527         memset(&ecfg, 0, sizeof(ecfg));
  528         cfg.ext = &ecfg;
  529         if ((error = sti_inqcfg(scr, &cfg))) {
  530                 aprint_error(": error %d inquiring config\n", error);
  531                 goto fail;
  532         }
  533 
  534         /*
  535          * Older (rev 8.02) boards report wrong offset values,
  536          * similar to the displayable area size, at least in m68k mode.
  537          * Attempt to detect this and adjust here.
  538          */
  539         if (cfg.owidth == cfg.width &&
  540             cfg.oheight == cfg.height)
  541                 geometry_kluge = 1;
  542 
  543         if (geometry_kluge) {
  544                 scr->scr_cfg.oscr_width = cfg.owidth =
  545                     cfg.fbwidth - cfg.width;
  546                 scr->scr_cfg.oscr_height = cfg.oheight =
  547                     cfg.fbheight - cfg.height;
  548         }
  549 
  550         /*
  551          * Save a few fields for sti_describe_screen() later
  552          */
  553         scr->fbheight = cfg.fbheight;
  554         scr->fbwidth = cfg.fbwidth;
  555         scr->oheight = cfg.oheight;
  556         scr->owidth = cfg.owidth;
  557         memcpy(scr->name, cfg.name, sizeof(scr->name));
  558 
  559         if ((error = sti_init(scr, STI_TEXTMODE | flags))) {
  560                 aprint_error(": cannot initialize (%d)\n", error);
  561                 goto fail;
  562         }
  563 #ifdef STIDEBUG
  564         snprintb(buf, sizeof(buf), STI_INQCONF_BITS, cfg.attributes);
  565         DPRINTF(("conf: bpp=%d planes=%d attr=%s\n"
  566             "crt=0x%x:0x%x:0x%x hw=0x%x:0x%x:0x%x\n", cfg.bpp,
  567             cfg.planes, buf,
  568             ecfg.crt_config[0], ecfg.crt_config[1], ecfg.crt_config[2],
  569             ecfg.crt_hw[0], ecfg.crt_hw[1], ecfg.crt_hw[2]));
  570 #endif
  571         scr->scr_bpp = cfg.bppu;
  572 
  573         /*
  574          * Although scr->scr_ecfg.current_monitor is not filled by
  575          * sti_init() as expected, we can nevertheless walk the monitor
  576          * list, if there is any, and if we find a mode matching our
  577          * resolution, pick its font index.
  578          */
  579         if (dd->dd_montbl != 0) {
  580                 STI_ENABLE_ROM(rom->rom_softc);
  581 
  582                 for (i = 0; i < dd->dd_nmon; i++) {
  583                         u_int offs = dd->dd_montbl + 8 * i;
  584                         uint32_t m[2];
  585                         sti_mon_t mon = (void *)m;
  586                         if (rom->rom_devtype == STI_DEVTYPE1) {
  587                                 m[0] = parseword(4 * offs);
  588                                 m[1] = parseword(4 * (offs + 4));
  589                         } else {
  590                                 bus_space_read_region_stream_4(memt, romh, offs,
  591                                     (uint32_t *)mon, sizeof(*mon) / 4);
  592                         }
  593 
  594                         if (mon->width == scr->scr_cfg.scr_width &&
  595                             mon->height == scr->scr_cfg.scr_height) {
  596                                 fontindex = mon->font;
  597                                 break;
  598                         }
  599                 }
  600 
  601                 STI_DISABLE_ROM(rom->rom_softc);
  602 
  603                 DPRINTF(("font index: %d\n", fontindex));
  604         }
  605 
  606         if ((error = sti_fetchfonts(scr, &cfg, dd->dd_fntaddr, fontindex))) {
  607                 aprint_error(": cannot fetch fonts (%d)\n", error);
  608                 goto fail;
  609         }
  610 
  611         /*
  612          * setup screen descriptions:
  613          *      figure number of fonts supported;
  614          *      allocate wscons structures;
  615          *      calculate dimensions.
  616          */
  617 
  618         scr->scr_wsd.name = "std";
  619         scr->scr_wsd.ncols = cfg.width / scr->scr_curfont.width;
  620         scr->scr_wsd.nrows = cfg.height / scr->scr_curfont.height;
  621         scr->scr_wsd.textops = &sti_emulops;
  622         scr->scr_wsd.fontwidth = scr->scr_curfont.width;
  623         scr->scr_wsd.fontheight = scr->scr_curfont.height;
  624         scr->scr_wsd.capabilities = WSSCREEN_REVERSE;
  625 
  626         scr->scr_scrlist[0] = &scr->scr_wsd;
  627         scr->scr_screenlist.nscreens = 1;
  628         scr->scr_screenlist.screens = scr->scr_scrlist;
  629 
  630 #ifndef SMALL_KERNEL
  631         /*
  632          * Decide which board-specific routines to use.
  633          */
  634 
  635         switch (dd->dd_grid[0]) {
  636         case STI_DD_CRX:
  637                 scr->setupfb = ngle_elk_setupfb;
  638                 scr->putcmap = ngle_putcmap;
  639 
  640                 scr->reg10_value = 0x13601000;
  641                 if (scr->scr_bpp > 8)
  642                         scr->reg12_value = NGLE_BUFF1_CMAP3;
  643                 else
  644                         scr->reg12_value = NGLE_BUFF1_CMAP0;
  645                 scr->cmap_finish_register = NGLE_REG_1;
  646                 break;
  647 
  648         case STI_DD_TIMBER:
  649                 scr->setupfb = ngle_timber_setupfb;
  650                 scr->putcmap = ngle_putcmap;
  651 
  652                 scr->reg10_value = 0x13602000;
  653                 scr->reg12_value = NGLE_BUFF1_CMAP0;
  654                 scr->cmap_finish_register = NGLE_REG_1;
  655                 break;
  656 
  657         case STI_DD_ARTIST:
  658                 scr->setupfb = ngle_artist_setupfb;
  659                 scr->putcmap = ngle_putcmap;
  660 
  661                 scr->reg10_value = 0x13601000;
  662                 scr->reg12_value = NGLE_ARTIST_CMAP0;
  663                 scr->cmap_finish_register = NGLE_REG_26;
  664                 break;
  665 
  666         case STI_DD_EG:
  667                 scr->setupfb = ngle_artist_setupfb;
  668                 scr->putcmap = ngle_putcmap;
  669 
  670                 scr->reg10_value = 0x13601000;
  671                 if (scr->scr_bpp > 8) {
  672                         scr->reg12_value = NGLE_BUFF1_CMAP3;
  673                         scr->cmap_finish_register = NGLE_REG_1;
  674                 } else {
  675                         scr->reg12_value = NGLE_ARTIST_CMAP0;
  676                         scr->cmap_finish_register = NGLE_REG_26;
  677                 }
  678                 break;
  679 
  680         case STI_DD_GRX:
  681         case STI_DD_CRX24:
  682         case STI_DD_EVRX:
  683         case STI_DD_3X2V:
  684         case STI_DD_DUAL_CRX:
  685         case STI_DD_HCRX:
  686         case STI_DD_LEGO:
  687         case STI_DD_SUMMIT:
  688         case STI_DD_PINNACLE:
  689         default:
  690                 scr->setupfb = NULL;
  691                 scr->putcmap =
  692                     rom->scment == NULL ? NULL : ngle_default_putcmap;
  693                 break;
  694         }
  695 #endif
  696 
  697         return 0;
  698 
  699 fail:
  700         /* XXX free resources */
  701         if (scr->scr_ecfg.addr != NULL) {
  702                 free(scr->scr_ecfg.addr, M_DEVBUF);
  703                 scr->scr_ecfg.addr = NULL;
  704         }
  705 
  706         return ENXIO;
  707 }
  708 
  709 void
  710 sti_describe_screen(struct sti_softc *sc, struct sti_screen *scr)
  711 {
  712         struct sti_font *fp = &scr->scr_curfont;
  713 
  714         aprint_normal("%s: %s, %dx%d frame buffer, %dx%dx%d display\n",
  715             device_xname(sc->sc_dev), scr->name, scr->fbwidth, scr->fbheight,
  716             scr->scr_cfg.scr_width, scr->scr_cfg.scr_height, scr->scr_bpp);
  717 
  718         aprint_normal("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
  719             device_xname(sc->sc_dev), fp->width, fp->height,
  720             fp->type, fp->bpc, fp->first, fp->last);
  721 }
  722 
  723 void
  724 sti_describe(struct sti_softc *sc)
  725 {
  726         struct sti_rom *rom = sc->sc_rom;
  727         struct sti_dd *dd = &rom->rom_dd;
  728 
  729         aprint_normal(": rev %d.%02d;%d, ID 0x%08X%08X\n",
  730             dd->dd_grrev >> 4, dd->dd_grrev & 0xf,
  731             dd->dd_lrrev, dd->dd_grid[0], dd->dd_grid[1]);
  732 
  733         if (sc->sc_scr != NULL)
  734                 sti_describe_screen(sc, sc->sc_scr);
  735 }
  736 
  737 /*
  738  * Final part of attachment. On hppa where we use the PDC console
  739  * during autoconf, this has to be postponed until autoconf has
  740  * completed.
  741  */
  742 void
  743 sti_end_attach(struct sti_softc *sc)
  744 {
  745         struct sti_screen *scr = sc->sc_scr;
  746 
  747         if (scr == NULL)
  748                 return;
  749 #if NWSDISPLAY > 0
  750         else {
  751                 struct wsemuldisplaydev_attach_args waa;
  752                 scr->scr_wsmode = WSDISPLAYIO_MODE_EMUL;
  753 
  754                 waa.console = sc->sc_flags & STI_CONSOLE ? 1 : 0;
  755                 waa.scrdata = &scr->scr_screenlist;
  756                 waa.accessops = &sti_accessops;
  757                 waa.accesscookie = scr;
  758 
  759                 /* attach as console if required */
  760                 if (waa.console && !ISSET(sc->sc_flags, STI_ATTACHED)) {
  761                         long defattr;
  762 
  763                         sti_alloc_attr(scr, 0, 0, 0, &defattr);
  764                         wsdisplay_cnattach(&scr->scr_wsd, scr,
  765                             0, scr->scr_wsd.nrows - 1, defattr);
  766                         sc->sc_flags |= STI_ATTACHED;
  767                 }
  768 
  769                 config_found(sc->sc_dev, &waa, wsemuldisplaydevprint,
  770                     CFARGS_NONE);
  771         }
  772 #endif
  773 }
  774 
  775 u_int
  776 sti_rom_size(bus_space_tag_t memt, bus_space_handle_t romh)
  777 {
  778         int devtype;
  779         u_int romend;
  780 
  781         devtype = bus_space_read_1(memt, romh, 3);
  782         if (devtype == STI_DEVTYPE4) {
  783                 bus_space_read_region_stream_4(memt, romh, STI_DEV4_DD_ROMEND,
  784                     (uint32_t *)&romend, 1);
  785         } else {
  786                 romend = parseword(STI_DEV1_DD_ROMEND);
  787         }
  788 
  789         DPRINTF(("%s: %08x (%08x)\n", __func__, romend, round_page(romend)));
  790 
  791         return round_page(romend);
  792 }
  793 
  794 int
  795 sti_fetchfonts(struct sti_screen *scr, struct sti_inqconfout *cfg,
  796     uint32_t baseaddr, u_int fontindex)
  797 {
  798         struct sti_rom *rom = scr->scr_rom;
  799         bus_space_tag_t memt = rom->memt;
  800         bus_space_handle_t romh = rom->romh;
  801         struct sti_font *fp = &scr->scr_curfont;
  802         uint32_t addr;
  803         int size;
  804 #ifdef notyet
  805         int uc;
  806         struct {
  807                 struct sti_unpmvflags flags;
  808                 struct sti_unpmvin in;
  809                 struct sti_unpmvout out;
  810         } a;
  811 #endif
  812 
  813         /*
  814          * Get the first PROM font in memory
  815          */
  816 
  817         STI_ENABLE_ROM(rom->rom_softc);
  818 
  819 rescan:
  820         addr = baseaddr;
  821         do {
  822                 if (rom->rom_devtype == STI_DEVTYPE1) {
  823                         fp->first  = parseshort(addr + 0x00);
  824                         fp->last   = parseshort(addr + 0x08);
  825                         fp->width  = bus_space_read_1(memt, romh, addr + 0x13);
  826                         fp->height = bus_space_read_1(memt, romh, addr + 0x17);
  827                         fp->type   = bus_space_read_1(memt, romh, addr + 0x1b);
  828                         fp->bpc    = bus_space_read_1(memt, romh, addr + 0x1f);
  829                         fp->next   = parseword(addr + 0x20);
  830                         fp->uheight= bus_space_read_1(memt, romh, addr + 0x33);
  831                         fp->uoffset= bus_space_read_1(memt, romh, addr + 0x37);
  832                 } else {        /* STI_DEVTYPE4 */
  833                         bus_space_read_region_stream_4(memt, romh, addr,
  834                             (uint32_t *)fp, sizeof(struct sti_font) / 4);
  835                 }
  836 
  837 #ifdef STIDEBUG
  838                 STI_DISABLE_ROM(rom->rom_softc);
  839                 DPRINTF(("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
  840                     device_xname(scr->scr_rom->rom_softc->sc_dev), fp->width,
  841                     fp->height, fp->type, fp->bpc, fp->first, fp->last));
  842                 STI_ENABLE_ROM(rom->rom_softc);
  843 #endif
  844 
  845                 if (fontindex == 0) {
  846                         size = sizeof(struct sti_font) +
  847                             (fp->last - fp->first + 1) * fp->bpc;
  848                         if (rom->rom_devtype == STI_DEVTYPE1)
  849                                 size *= 4;
  850                         scr->scr_romfont = malloc(size, M_DEVBUF, M_WAITOK);
  851 
  852                         bus_space_read_region_stream_4(memt, romh, addr,
  853                             (uint32_t *)scr->scr_romfont, size / 4);
  854                         break;
  855                 }
  856 
  857                 addr = baseaddr + fp->next;
  858                 fontindex--;
  859         } while (fp->next != 0);
  860 
  861         /*
  862          * If our font index was bogus, we did not find the expected font.
  863          * In this case, pick the first one and be done with it.
  864          */
  865         if (fp->next == 0 && scr->scr_romfont == NULL) {
  866                 fontindex = 0;
  867                 goto rescan;
  868         }
  869 
  870         STI_DISABLE_ROM(rom->rom_softc);
  871 
  872 #ifdef notyet
  873         /*
  874          * If there is enough room in the off-screen framebuffer memory,
  875          * display all the characters there in order to display them
  876          * faster with blkmv operations rather than unpmv later on.
  877          */
  878         if (size <= cfg->fbheight *
  879             (cfg->fbwidth - cfg->width - cfg->owidth)) {
  880                 memset(&a, 0, sizeof(a));
  881                 a.flags.flags = STI_UNPMVF_WAIT;
  882                 a.in.fg_colour = STI_COLOUR_WHITE;
  883                 a.in.bg_colour = STI_COLOUR_BLACK;
  884                 a.in.font_addr = scr->scr_romfont;
  885 
  886                 scr->scr_fontmaxcol = cfg->fbheight / fp->height;
  887                 scr->scr_fontbase = cfg->width + cfg->owidth;
  888                 for (uc = fp->first; uc <= fp->last; uc++) {
  889                         a.in.x = ((uc - fp->first) / scr->scr_fontmaxcol) *
  890                             fp->width + scr->scr_fontbase;
  891                         a.in.y = ((uc - fp->first) % scr->scr_fontmaxcol) *
  892                             fp->height;
  893                         a.in.index = uc;
  894 
  895                         (*scr->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
  896                         if (a.out.errno) {
  897                                 aprint_error_dev(sc->sc_dev, "unpmv %d "
  898                                     "returned %d\n", uc, a.out.errno);
  899                                 return 0;
  900                         }
  901                 }
  902 
  903                 free(scr->scr_romfont, M_DEVBUF);
  904                 scr->scr_romfont = NULL;
  905         }
  906 #endif
  907 
  908         return 0;
  909 }
  910 
  911 /*
  912  * Wrappers around STI code pointers
  913  */
  914 
  915 int
  916 sti_init(struct sti_screen *scr, int mode)
  917 {
  918         struct sti_rom *rom = scr->scr_rom;
  919         struct {
  920                 struct sti_initflags flags;
  921                 struct sti_initin in;
  922                 struct sti_einitin ein;
  923                 struct sti_initout out;
  924         } a;
  925 
  926         KASSERT(rom != NULL);
  927         memset(&a, 0, sizeof(a));
  928 
  929         a.flags.flags = STI_INITF_WAIT | STI_INITF_EBET;
  930         if ((mode & STI_TEXTMODE) != 0) {
  931                 a.flags.flags |= STI_INITF_TEXT | STI_INITF_CMB |
  932                     STI_INITF_PBET | STI_INITF_PBETI | STI_INITF_ICMT;
  933         } else {
  934                 a.flags.flags |= STI_INITF_NTEXT;
  935         }
  936         if ((mode & STI_CLEARSCR) != 0)
  937                 a.flags.flags |= STI_INITF_CLEAR;
  938 
  939         a.in.text_planes = 1;
  940         a.in.ext_in = &a.ein;
  941 
  942         DPRINTF(("%s: init,%p(%x, %p, %p, %p)\n",
  943             device_xname(rom->rom_softc->sc_dev), rom->init, a.flags.flags,
  944             &a.in, &a.out, &scr->scr_cfg));
  945 
  946         (*rom->init)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
  947 
  948         if (a.out.text_planes != a.in.text_planes)
  949                 return -1;      /* not colliding with sti errno values */
  950         return a.out.errno;
  951 }
  952 
  953 int
  954 sti_inqcfg(struct sti_screen *scr, struct sti_inqconfout *out)
  955 {
  956         struct sti_rom *rom = scr->scr_rom;
  957         struct {
  958                 struct sti_inqconfflags flags;
  959                 struct sti_inqconfin in;
  960         } a;
  961 
  962         memset(&a, 0, sizeof(a));
  963 
  964         a.flags.flags = STI_INQCONFF_WAIT;
  965         (*rom->inqconf)(&a.flags, &a.in, out, &scr->scr_cfg);
  966 
  967         return out->errno;
  968 }
  969 
  970 void
  971 sti_bmove(struct sti_screen *scr, int x1, int y1, int x2, int y2, int h, int w,
  972     enum sti_bmove_funcs f)
  973 {
  974         struct sti_rom *rom = scr->scr_rom;
  975         struct {
  976                 struct sti_blkmvflags flags;
  977                 struct sti_blkmvin in;
  978                 struct sti_blkmvout out;
  979         } a;
  980 
  981         memset(&a, 0, sizeof(a));
  982 
  983         a.flags.flags = STI_BLKMVF_WAIT;
  984         switch (f) {
  985         case bmf_clear:
  986                 a.flags.flags |= STI_BLKMVF_CLR;
  987                 a.in.bg_colour = STI_COLOUR_BLACK;
  988                 break;
  989         case bmf_underline:
  990         case bmf_copy:
  991                 a.in.fg_colour = STI_COLOUR_WHITE;
  992                 a.in.bg_colour = STI_COLOUR_BLACK;
  993                 break;
  994         case bmf_invert:
  995                 a.flags.flags |= STI_BLKMVF_COLR;
  996                 a.in.fg_colour = STI_COLOUR_BLACK;
  997                 a.in.bg_colour = STI_COLOUR_WHITE;
  998                 break;
  999         }
 1000         a.in.srcx = x1;
 1001         a.in.srcy = y1;
 1002         a.in.dstx = x2;
 1003         a.in.dsty = y2;
 1004         a.in.height = h;
 1005         a.in.width = w;
 1006 
 1007         (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
 1008 #ifdef STIDEBUG
 1009         if (a.out.errno)
 1010                 printf("%s: blkmv returned %d\n",
 1011                     device_xname(rom->rom_softc->sc_dev), a.out.errno);
 1012 #endif
 1013 }
 1014 
 1015 int
 1016 sti_setcment(struct sti_screen *scr, u_int i, u_char r, u_char g, u_char b)
 1017 {
 1018         struct sti_rom *rom = scr->scr_rom;
 1019         struct {
 1020                 struct sti_scmentflags flags;
 1021                 struct sti_scmentin in;
 1022                 struct sti_scmentout out;
 1023         } a;
 1024 
 1025         memset(&a, 0, sizeof(a));
 1026 
 1027         a.flags.flags = STI_SCMENTF_WAIT;
 1028         a.in.entry = i;
 1029         a.in.value = (r << 16) | (g << 8) | b;
 1030 
 1031         (*rom->scment)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
 1032 
 1033         return a.out.errno;
 1034 }
 1035 
 1036 /*
 1037  * wsdisplay accessops
 1038  */
 1039 int
 1040 sti_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
 1041 {
 1042         struct sti_screen *scr = (struct sti_screen *)v;
 1043         struct wsdisplay_fbinfo *wdf;
 1044         struct wsdisplay_cmap *cmapp;
 1045         u_int mode, idx, count;
 1046         int ret;
 1047 
 1048         ret = 0;
 1049         switch (cmd) {
 1050         case WSDISPLAYIO_GMODE:
 1051                 *(u_int *)data = scr->scr_wsmode;
 1052                 break;
 1053 
 1054         case WSDISPLAYIO_SMODE:
 1055                 mode = *(u_int *)data;
 1056                 switch (mode) {
 1057                 case WSDISPLAYIO_MODE_EMUL:
 1058                         if (scr->scr_wsmode != WSDISPLAYIO_MODE_EMUL)
 1059                                 ret = sti_init(scr, STI_TEXTMODE);
 1060                         break;
 1061                 case WSDISPLAYIO_MODE_DUMBFB:
 1062                         if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) {
 1063                                 sti_init(scr, 0);
 1064                                 if (scr->setupfb != NULL)
 1065                                         scr->setupfb(scr);
 1066                                 else
 1067 #if 0
 1068                                         ret = sti_init(scr, STI_FBMODE);
 1069 #else
 1070                                         ret = EINVAL;
 1071 #endif
 1072                         }
 1073                         break;
 1074                 case WSDISPLAYIO_MODE_MAPPED:
 1075                 default:
 1076                         ret = EINVAL;
 1077                         break;
 1078                 }
 1079                 if (ret == 0)
 1080                         scr->scr_wsmode = mode;
 1081                 break;
 1082 
 1083         case WSDISPLAYIO_GTYPE:
 1084                 *(u_int *)data = WSDISPLAY_TYPE_STI;
 1085                 break;
 1086 
 1087         case WSDISPLAYIO_GINFO:
 1088                 wdf = (struct wsdisplay_fbinfo *)data;
 1089                 wdf->height = scr->scr_cfg.scr_height;
 1090                 wdf->width  = scr->scr_cfg.scr_width;
 1091                 wdf->depth  = scr->scr_bpp;
 1092                 if (scr->putcmap == NULL || scr->scr_bpp > 8)
 1093                         wdf->cmsize = 0;
 1094                 else
 1095                         wdf->cmsize = STI_NCMAP;
 1096                 break;
 1097 
 1098         case WSDISPLAYIO_LINEBYTES:
 1099                 if (scr->scr_bpp > 8)
 1100                         *(u_int *)data = scr->scr_cfg.fb_width * 4;
 1101                 else
 1102                         *(u_int *)data = scr->scr_cfg.fb_width;
 1103                 break;
 1104 
 1105         case WSDISPLAYIO_GETCMAP:
 1106                 if (scr->putcmap == NULL || scr->scr_bpp > 8)
 1107                         return ENODEV;
 1108                 cmapp = (struct wsdisplay_cmap *)data;
 1109                 idx = cmapp->index;
 1110                 count = cmapp->count;
 1111                 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
 1112                         return EINVAL;
 1113                 if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
 1114                         break;
 1115                 if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
 1116                         break;
 1117                 if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
 1118                         break;
 1119                 break;
 1120 
 1121         case WSDISPLAYIO_PUTCMAP:
 1122                 if (scr->putcmap == NULL || scr->scr_bpp > 8)
 1123                         return ENODEV;
 1124                 if (scr->scr_wsmode == WSDISPLAYIO_MODE_EMUL) {
 1125                         /*
 1126                          * The hardware palette settings are handled by
 1127                          * the STI ROM in STI_TEXTMODE and changing cmap
 1128                          * could cause mangled text colors at least on CRX.
 1129                          * Updating CMAP in EMUL mode isn't expected anyway
 1130                          * so just ignore it.
 1131                          */
 1132                         return 0;
 1133                 }
 1134                 cmapp = (struct wsdisplay_cmap *)data;
 1135                 idx = cmapp->index;
 1136                 count = cmapp->count;
 1137                 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
 1138                         return EINVAL;
 1139                 if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
 1140                         break;
 1141                 if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
 1142                         break;
 1143                 if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
 1144                         break;
 1145                 ret = scr->putcmap(scr, idx, count);
 1146                 break;
 1147 
 1148         case WSDISPLAYIO_SVIDEO:
 1149         case WSDISPLAYIO_GVIDEO:
 1150         case WSDISPLAYIO_GCURPOS:
 1151         case WSDISPLAYIO_SCURPOS:
 1152         case WSDISPLAYIO_GCURMAX:
 1153         case WSDISPLAYIO_GCURSOR:
 1154         case WSDISPLAYIO_SCURSOR:
 1155         default:
 1156                 return ENOTTY;  /* not supported yet */
 1157         }
 1158 
 1159         return ret;
 1160 }
 1161 
 1162 paddr_t
 1163 sti_mmap(void *v, void *vs, off_t offset, int prot)
 1164 {
 1165         struct sti_screen *scr = (struct sti_screen *)v;
 1166         struct sti_rom *rom = scr->scr_rom;
 1167         paddr_t pa;
 1168 
 1169         if ((offset & PAGE_MASK) != 0)
 1170                 return -1;
 1171 
 1172         if (offset < 0 || offset >= scr->fblen)
 1173                 return -1;
 1174 
 1175         if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB)
 1176                 return -1;
 1177 
 1178         pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot,
 1179             BUS_SPACE_MAP_LINEAR);
 1180 
 1181         if (pa == -1)
 1182                 pa = scr->fbaddr + offset;
 1183 
 1184         return pa;
 1185 }
 1186 
 1187 int
 1188 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
 1189     int *cxp, int *cyp, long *defattr)
 1190 {
 1191         struct sti_screen *scr = (struct sti_screen *)v;
 1192 
 1193         if (scr->scr_nscreens > 0)
 1194                 return ENOMEM;
 1195 
 1196         *cookiep = scr;
 1197         *cxp = 0;
 1198         *cyp = 0;
 1199         sti_alloc_attr(scr, 0, 0, 0, defattr);
 1200         scr->scr_nscreens++;
 1201         return 0;
 1202 }
 1203 
 1204 void
 1205 sti_free_screen(void *v, void *cookie)
 1206 {
 1207         struct sti_screen *scr = (struct sti_screen *)v;
 1208 
 1209         scr->scr_nscreens--;
 1210 }
 1211 
 1212 int
 1213 sti_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
 1214     void *cbarg)
 1215 {
 1216 #if 0
 1217         struct sti_screen *scr = (struct sti_screen *)v;
 1218 #endif
 1219 
 1220         return 0;
 1221 }
 1222 
 1223 int
 1224 sti_load_font(void *v, void *cookie, struct wsdisplay_font *font)
 1225 {
 1226 #if 0
 1227         struct sti_screen *scr = (struct sti_screen *)v;
 1228 #endif
 1229 
 1230         return -1;
 1231 }
 1232 
 1233 /*
 1234  * wsdisplay emulops
 1235  */
 1236 void
 1237 sti_cursor(void *v, int on, int row, int col)
 1238 {
 1239         struct sti_screen *scr = (struct sti_screen *)v;
 1240         struct sti_font *fp = &scr->scr_curfont;
 1241 
 1242         sti_bmove(scr,
 1243             col * fp->width, row * fp->height,
 1244             col * fp->width, row * fp->height,
 1245             fp->height, fp->width, bmf_invert);
 1246 }
 1247 
 1248 /*
 1249  * ISO 8859-1 part of Unicode to HP Roman font index conversion array.
 1250  */
 1251 static const uint8_t
 1252 sti_unitoroman[0x100 - 0xa0] = {
 1253         0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc,    0, 0xbd,
 1254         0xab,    0, 0xf9, 0xfb,    0, 0xf6,    0, 0xb0,
 1255 
 1256         0xb3, 0xfe,    0,    0, 0xa8, 0xf3, 0xf4, 0xf2,
 1257            0,    0, 0xfa, 0xfd, 0xf7, 0xf8,    0, 0xb9,
 1258 
 1259         0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4,
 1260         0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7,
 1261 
 1262         0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda,    0,
 1263         0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde,
 1264 
 1265         0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5,
 1266         0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd,
 1267 
 1268         0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce,    0,
 1269         0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef
 1270 };
 1271 
 1272 int
 1273 sti_mapchar(void *v, int uni, u_int *index)
 1274 {
 1275         struct sti_screen *scr = (struct sti_screen *)v;
 1276         struct sti_font *fp = &scr->scr_curfont;
 1277         int c;
 1278 
 1279         switch (fp->type) {
 1280         case STI_FONT_HPROMAN8:
 1281                 if (uni >= 0x80 && uni < 0xa0)
 1282                         c = -1;
 1283                 else if (uni >= 0xa0 && uni < 0x100) {
 1284                         c = (int)sti_unitoroman[uni - 0xa0];
 1285                         if (c == 0)
 1286                                 c = -1;
 1287                 } else
 1288                         c = uni;
 1289                 break;
 1290         default:
 1291                 c = uni;
 1292                 break;
 1293         }
 1294 
 1295         if (c == -1 || c < fp->first || c > fp->last) {
 1296                 *index = ' ';
 1297                 return 0;
 1298         }
 1299 
 1300         *index = c;
 1301         return 5;
 1302 }
 1303 
 1304 void
 1305 sti_putchar(void *v, int row, int col, u_int uc, long attr)
 1306 {
 1307         struct sti_screen *scr = (struct sti_screen *)v;
 1308         struct sti_rom *rom = scr->scr_rom;
 1309         struct sti_font *fp = &scr->scr_curfont;
 1310         int bg, fg;
 1311 
 1312         fg = WSATTR_UNPACK_FG(attr);
 1313         bg = WSATTR_UNPACK_BG(attr);
 1314 
 1315         if (scr->scr_romfont != NULL) {
 1316                 /*
 1317                  * Font is in memory, use unpmv
 1318                  */
 1319                 struct {
 1320                         struct sti_unpmvflags flags;
 1321                         struct sti_unpmvin in;
 1322                         struct sti_unpmvout out;
 1323                 } a;
 1324 
 1325                 memset(&a, 0, sizeof(a));
 1326 
 1327                 a.flags.flags = STI_UNPMVF_WAIT;
 1328                 a.in.fg_colour = fg;
 1329                 a.in.bg_colour = bg;
 1330                 a.in.x = col * fp->width;
 1331                 a.in.y = row * fp->height;
 1332                 a.in.font_addr = scr->scr_romfont;
 1333                 a.in.index = uc;
 1334 
 1335                 (*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
 1336         } else {
 1337                 /*
 1338                  * Font is in frame buffer, use blkmv
 1339                  */
 1340                 struct {
 1341                         struct sti_blkmvflags flags;
 1342                         struct sti_blkmvin in;
 1343                         struct sti_blkmvout out;
 1344                 } a;
 1345 
 1346                 memset(&a, 0, sizeof(a));
 1347 
 1348                 a.flags.flags = STI_BLKMVF_WAIT;
 1349                 a.in.fg_colour = fg;
 1350                 a.in.bg_colour = bg;
 1351 
 1352                 a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) *
 1353                     fp->width + scr->scr_fontbase;
 1354                 a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) *
 1355                     fp->height;
 1356                 a.in.dstx = col * fp->width;
 1357                 a.in.dsty = row * fp->height;
 1358                 a.in.height = fp->height;
 1359                 a.in.width = fp->width;
 1360 
 1361                 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
 1362         }
 1363 }
 1364 
 1365 void
 1366 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols)
 1367 {
 1368         struct sti_screen *scr = (struct sti_screen *)v;
 1369         struct sti_font *fp = &scr->scr_curfont;
 1370 
 1371         sti_bmove(scr,
 1372             srccol * fp->width, row * fp->height,
 1373             dstcol * fp->width, row * fp->height,
 1374             fp->height, ncols * fp->width, bmf_copy);
 1375 }
 1376 
 1377 void
 1378 sti_erasecols(void *v, int row, int startcol, int ncols, long attr)
 1379 {
 1380         struct sti_screen *scr = (struct sti_screen *)v;
 1381         struct sti_font *fp = &scr->scr_curfont;
 1382 
 1383         sti_bmove(scr,
 1384             startcol * fp->width, row * fp->height,
 1385             startcol * fp->width, row * fp->height,
 1386             fp->height, ncols * fp->width, bmf_clear);
 1387 }
 1388 
 1389 void
 1390 sti_copyrows(void *v, int srcrow, int dstrow, int nrows)
 1391 {
 1392         struct sti_screen *scr = (struct sti_screen *)v;
 1393         struct sti_font *fp = &scr->scr_curfont;
 1394 
 1395         sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height,
 1396             nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy);
 1397 }
 1398 
 1399 void
 1400 sti_eraserows(void *v, int srcrow, int nrows, long attr)
 1401 {
 1402         struct sti_screen *scr = (struct sti_screen *)v;
 1403         struct sti_font *fp = &scr->scr_curfont;
 1404 
 1405         sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height,
 1406             nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear);
 1407 }
 1408 
 1409 int
 1410 sti_alloc_attr(void *v, int fg, int bg, int flags, long *pattr)
 1411 {
 1412 #if 0
 1413         struct sti_screen *scr = (struct sti_screen *)v;
 1414 #endif
 1415 
 1416         if ((flags & (WSATTR_HILIT | WSATTR_BLINK |
 1417             WSATTR_UNDERLINE | WSATTR_WSCOLORS)) != 0)
 1418                 return EINVAL;
 1419         if ((flags & WSATTR_REVERSE) != 0) {
 1420                 fg = STI_COLOUR_BLACK;
 1421                 bg = STI_COLOUR_WHITE;
 1422         } else {
 1423                 fg = STI_COLOUR_WHITE;
 1424                 bg = STI_COLOUR_BLACK;
 1425         }
 1426 
 1427         *pattr = WSATTR_PACK(fg, bg, flags);
 1428         return 0;
 1429 }
 1430 
 1431 /*
 1432  * Early console support.  Only used on hp300, currently
 1433  */
 1434 int
 1435 sti_cnattach(struct sti_rom *rom, struct sti_screen *scr, bus_space_tag_t memt,
 1436     bus_addr_t *bases, u_int codebase)
 1437 {
 1438         bus_space_handle_t romh;
 1439         u_int romend;
 1440         int error;
 1441         long defattr;
 1442 
 1443         if ((error = bus_space_map(memt, bases[0], PAGE_SIZE, 0, &romh)) != 0)
 1444                 return error;
 1445 
 1446         /*
 1447          * Compute real PROM size
 1448          */
 1449         romend = sti_rom_size(memt, romh);
 1450 
 1451         bus_space_unmap(memt, romh, PAGE_SIZE);
 1452 
 1453         if ((error = bus_space_map(memt, bases[0], romend, 0, &romh)) != 0)
 1454                 return error;
 1455 
 1456         bases[0] = romh;
 1457         if (sti_rom_setup(rom, memt, memt, romh, bases, codebase) != 0)
 1458                 return -1;
 1459         scr->scr_rom = rom;
 1460         if (sti_screen_setup(scr, STI_CLEARSCR) != 0)
 1461                 return -1;
 1462 
 1463         sti_alloc_attr(scr, 0, 0, 0, &defattr);
 1464         wsdisplay_cnattach(&scr->scr_wsd, scr, 0, 0, defattr);
 1465 
 1466         return 0;
 1467 }
 1468 
 1469 int
 1470 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count)
 1471 {
 1472         int i, ret;
 1473 
 1474         for (i = idx + count - 1; i >= (int)idx; i--)
 1475                 if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i],
 1476                     scr->scr_gcmap[i], scr->scr_bcmap[i])))
 1477                         return EINVAL;
 1478 
 1479         return 0;
 1480 }
 1481 
 1482 #ifndef SMALL_KERNEL
 1483 
 1484 void    ngle_setup_hw(bus_space_tag_t, bus_space_handle_t);
 1485 void    ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t);
 1486 void    ngle_setup_attr_planes(struct sti_screen *scr);
 1487 void    ngle_setup_bt458(struct sti_screen *scr);
 1488 
 1489 #define ngle_bt458_write(memt, memh, r, v) \
 1490         bus_space_write_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
 1491 
 1492 void
 1493 ngle_artist_setupfb(struct sti_screen *scr)
 1494 {
 1495         struct sti_rom *rom = scr->scr_rom;
 1496         bus_space_tag_t memt = rom->memt;
 1497         bus_space_handle_t memh = rom->regh[2];
 1498 
 1499         ngle_setup_bt458(scr);
 1500 
 1501         ngle_setup_hw(memt, memh);
 1502         ngle_setup_fb(memt, memh, scr->reg10_value);
 1503 
 1504         ngle_setup_attr_planes(scr);
 1505 
 1506         ngle_setup_hw(memt, memh);
 1507         bus_space_write_4(memt, memh, NGLE_REG_21,
 1508             bus_space_read_4(memt, memh, NGLE_REG_21) | 0x0a000000);
 1509         bus_space_write_4(memt, memh, NGLE_REG_27,
 1510             bus_space_read_4(memt, memh, NGLE_REG_27) | 0x00800000);
 1511 }
 1512 
 1513 void
 1514 ngle_elk_setupfb(struct sti_screen *scr)
 1515 {
 1516         struct sti_rom *rom = scr->scr_rom;
 1517         bus_space_tag_t memt = rom->memt;
 1518         bus_space_handle_t memh = rom->regh[2];
 1519 
 1520         ngle_setup_bt458(scr);
 1521 
 1522         ngle_setup_hw(memt, memh);
 1523         ngle_setup_fb(memt, memh, scr->reg10_value);
 1524 
 1525         ngle_setup_attr_planes(scr);
 1526 
 1527         ngle_setup_hw(memt, memh);
 1528         /* enable overlay planes in Bt458 command register */
 1529         ngle_bt458_write(memt, memh, 0x0c, 0x06);
 1530         ngle_bt458_write(memt, memh, 0x0e, 0x43);
 1531 }
 1532 
 1533 void
 1534 ngle_timber_setupfb(struct sti_screen *scr)
 1535 {
 1536         struct sti_rom *rom = scr->scr_rom;
 1537         bus_space_tag_t memt = rom->memt;
 1538         bus_space_handle_t memh = rom->regh[2];
 1539 
 1540         ngle_setup_bt458(scr);
 1541 
 1542         ngle_setup_hw(memt, memh);
 1543         /* enable overlay planes in Bt458 command register */
 1544         ngle_bt458_write(memt, memh, 0x0c, 0x06);
 1545         ngle_bt458_write(memt, memh, 0x0e, 0x43);
 1546 }
 1547 
 1548 void
 1549 ngle_setup_bt458(struct sti_screen *scr)
 1550 {
 1551         struct sti_rom *rom = scr->scr_rom;
 1552         bus_space_tag_t memt = rom->memt;
 1553         bus_space_handle_t memh = rom->regh[2];
 1554 
 1555         ngle_setup_hw(memt, memh);
 1556         /* set Bt458 read mask register to all planes */
 1557         ngle_bt458_write(memt, memh, 0x08, 0x04);
 1558         ngle_bt458_write(memt, memh, 0x0a, 0xff);
 1559 }
 1560 
 1561 void
 1562 ngle_setup_attr_planes(struct sti_screen *scr)
 1563 {
 1564         struct sti_rom *rom = scr->scr_rom;
 1565         bus_space_tag_t memt = rom->memt;
 1566         bus_space_handle_t memh = rom->regh[2];
 1567 
 1568         ngle_setup_hw(memt, memh);
 1569         bus_space_write_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
 1570         bus_space_write_4(memt, memh, NGLE_REG_14, 0x23000302);
 1571         bus_space_write_4(memt, memh, NGLE_REG_12, scr->reg12_value);
 1572         bus_space_write_4(memt, memh, NGLE_REG_8, 0xffffffff);
 1573 
 1574         bus_space_write_4(memt, memh, NGLE_REG_6, 0x00000000);
 1575         bus_space_write_4(memt, memh, NGLE_REG_9,
 1576             (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height);
 1577         bus_space_write_4(memt, memh, NGLE_REG_6, 0x05000000);
 1578         bus_space_write_4(memt, memh, NGLE_REG_9, 0x00040001);
 1579 
 1580         ngle_setup_hw(memt, memh);
 1581         bus_space_write_4(memt, memh, NGLE_REG_12, 0x00000000);
 1582 
 1583         ngle_setup_fb(memt, memh, scr->reg10_value);
 1584 }
 1585 
 1586 int
 1587 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count)
 1588 {
 1589         struct sti_rom *rom = scr->scr_rom;
 1590         bus_space_tag_t memt = rom->memt;
 1591         bus_space_handle_t memh = rom->regh[2];
 1592         uint8_t *r, *g, *b;
 1593         uint32_t cmap_finish;
 1594 
 1595         if (scr->scr_bpp > 8)
 1596                 cmap_finish = 0x83000100;
 1597         else
 1598                 cmap_finish = 0x80000100;
 1599 
 1600         r = scr->scr_rcmap + idx;
 1601         g = scr->scr_gcmap + idx;
 1602         b = scr->scr_bcmap + idx;
 1603 
 1604         ngle_setup_hw(memt, memh);
 1605         bus_space_write_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
 1606         bus_space_write_4(memt, memh, NGLE_REG_14, 0x03000300);
 1607         bus_space_write_4(memt, memh, NGLE_REG_13, 0xffffffff);
 1608 
 1609         while (count-- != 0) {
 1610                 ngle_setup_hw(memt, memh);
 1611                 bus_space_write_4(memt, memh, NGLE_REG_3, 0x400 | (idx << 2));
 1612                 bus_space_write_4(memt, memh, NGLE_REG_4,
 1613                     (*r << 16) | (*g << 8) | *b);
 1614 
 1615                 idx++;
 1616                 r++, g++, b++;
 1617         }
 1618 
 1619         bus_space_write_4(memt, memh, NGLE_REG_2, 0x400);
 1620         bus_space_write_4(memt, memh, scr->cmap_finish_register, cmap_finish);
 1621         ngle_setup_fb(memt, memh, scr->reg10_value);
 1622 
 1623 
 1624         return 0;
 1625 }
 1626 
 1627 void
 1628 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh)
 1629 {
 1630         uint8_t stat;
 1631 
 1632         do {
 1633                 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
 1634                 if (stat == 0)
 1635                         stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
 1636         } while (stat != 0);
 1637 }
 1638 
 1639 void
 1640 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10)
 1641 {
 1642 
 1643         ngle_setup_hw(memt, memh);
 1644         bus_space_write_4(memt, memh, NGLE_REG_10, reg10);
 1645         bus_space_write_4(memt, memh, NGLE_REG_14, 0x83000300);
 1646         ngle_setup_hw(memt, memh);
 1647         bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
 1648 }
 1649 #endif  /* SMALL_KERNEL */

Cache object: 272e7d0fa23a61613831b0a1b57aec6e


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