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/igsfb.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: igsfb.c,v 1.60 2021/08/07 16:19:12 thorpej Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2002, 2003 Valeriy E. Ushakov
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission
   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 BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 /*
   31  * Integraphics Systems IGA 168x and CyberPro series.
   32  */
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: igsfb.c,v 1.60 2021/08/07 16:19:12 thorpej Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/device.h>
   40 #include <sys/malloc.h>
   41 #include <sys/ioctl.h>
   42 
   43 #include <sys/bus.h>
   44 
   45 #include <dev/wscons/wsdisplayvar.h>
   46 #include <dev/wscons/wsconsio.h>
   47 #include <dev/wsfont/wsfont.h>
   48 #include <dev/rasops/rasops.h>
   49 
   50 #include <dev/wscons/wsdisplay_vconsvar.h>
   51 
   52 #include <dev/ic/igsfbreg.h>
   53 #include <dev/ic/igsfbvar.h>
   54 
   55 
   56 struct igsfb_devconfig igsfb_console_dc = {
   57         .dc_mmap = NULL,
   58         .dc_modestring = "",
   59 };
   60 
   61 /*
   62  * wsscreen
   63  */
   64 
   65 /* filled from rasops_info in igsfb_init_wsdisplay */
   66 static struct wsscreen_descr igsfb_stdscreen = {
   67         .name = "std",
   68 };
   69 
   70 static const struct wsscreen_descr *_igsfb_scrlist[] = {
   71         &igsfb_stdscreen,
   72 };
   73 
   74 static const struct wsscreen_list igsfb_screenlist = {
   75         .nscreens = sizeof(_igsfb_scrlist) / sizeof(_igsfb_scrlist[0]),
   76         .screens = _igsfb_scrlist,
   77 };
   78 
   79 
   80 /*
   81  * wsdisplay_accessops
   82  */
   83 
   84 static int      igsfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
   85 static paddr_t  igsfb_mmap(void *, void *, off_t, int);
   86 
   87 static struct wsdisplay_accessops igsfb_accessops = {
   88         .ioctl = igsfb_ioctl,
   89         .mmap = igsfb_mmap,
   90 };
   91 
   92 
   93 /*
   94  * acceleration
   95  */
   96 static int      igsfb_make_text_cursor(struct igsfb_devconfig *,
   97                                        struct vcons_screen *);
   98 static void     igsfb_accel_cursor(void *, int, int, int);
   99 
  100 static int      igsfb_accel_wait(struct igsfb_devconfig *);
  101 static void     igsfb_accel_fill(struct igsfb_devconfig *,
  102                                  uint32_t, uint32_t, uint16_t, uint16_t);
  103 static void     igsfb_accel_copy(struct igsfb_devconfig *,
  104                                  uint32_t, uint32_t, uint16_t, uint16_t);
  105 
  106 static void     igsfb_accel_copycols(void *, int, int, int, int);
  107 static void     igsfb_accel_erasecols(void *, int, int, int, long);
  108 static void     igsfb_accel_copyrows(void *, int, int, int);
  109 static void     igsfb_accel_eraserows(void *, int, int, long);
  110 static void     igsfb_accel_putchar(void *, int, int, u_int, long);
  111 
  112 
  113 /*
  114  * internal functions
  115  */
  116 static int      igsfb_init_video(struct igsfb_devconfig *);
  117 static void     igsfb_init_cmap(struct igsfb_devconfig *);
  118 static uint16_t igsfb_spread_bits_8(uint8_t);
  119 static void     igsfb_init_bit_table(struct igsfb_devconfig *);
  120 static void     igsfb_init_wsdisplay(void *, struct vcons_screen *, int,
  121                                      long *);
  122 
  123 
  124 static void     igsfb_blank_screen(struct igsfb_devconfig *, int);
  125 static int      igsfb_get_cmap(struct igsfb_devconfig *,
  126                                struct wsdisplay_cmap *);
  127 static int      igsfb_set_cmap(struct igsfb_devconfig *,
  128                                const struct wsdisplay_cmap *);
  129 static void     igsfb_update_cmap(struct igsfb_devconfig *, u_int, u_int);
  130 static void     igsfb_set_curpos(struct igsfb_devconfig *,
  131                                  const struct wsdisplay_curpos *);
  132 static void     igsfb_update_curpos(struct igsfb_devconfig *);
  133 static int      igsfb_get_cursor(struct igsfb_devconfig *,
  134                                  struct wsdisplay_cursor *);
  135 static int      igsfb_set_cursor(struct igsfb_devconfig *,
  136                                  const struct wsdisplay_cursor *);
  137 static void     igsfb_update_cursor(struct igsfb_devconfig *, u_int);
  138 static void     igsfb_convert_cursor_data(struct igsfb_devconfig *,
  139                                           u_int, u_int);
  140 
  141 
  142 int
  143 igsfb_cnattach_subr(struct igsfb_devconfig *dc)
  144 {
  145         struct rasops_info *ri;
  146         long defattr;
  147 
  148         KASSERT(dc == &igsfb_console_dc);
  149 
  150         igsfb_init_video(dc);
  151         dc->dc_vd.active = NULL;
  152         igsfb_init_wsdisplay(dc, &dc->dc_console, 1, &defattr);
  153 
  154         ri = &dc->dc_console.scr_ri;
  155         ri->ri_hw = &dc->dc_console;
  156         dc->dc_console.scr_cookie = dc;
  157 
  158         (*ri->ri_ops.allocattr)(ri,
  159                                 WS_DEFAULT_FG, /* fg */
  160                                 WS_DEFAULT_BG, /* bg */
  161                                 0,           /* wsattrs */
  162                                 &defattr);
  163 
  164         wsdisplay_cnattach(&igsfb_stdscreen,
  165                            ri,   /* emulcookie */
  166                            0, 0, /* cursor position */
  167                            defattr);
  168         return 0;
  169 }
  170 
  171 
  172 /*
  173  * Finish off the attach.  Bus specific attach method should have
  174  * enabled io and memory accesses and mapped io (and cop?) registers.
  175  */
  176 void
  177 igsfb_attach_subr(struct igsfb_softc *sc, int isconsole)
  178 {
  179         struct igsfb_devconfig *dc = sc->sc_dc;
  180         struct wsemuldisplaydev_attach_args waa;
  181         struct rasops_info *ri;
  182         long defattr;
  183 
  184         KASSERT(dc != NULL);
  185 
  186         if (!isconsole) {
  187                 igsfb_init_video(dc);
  188         }
  189 
  190         vcons_init(&dc->dc_vd, dc, &igsfb_stdscreen, &igsfb_accessops);
  191         dc->dc_vd.init_screen = igsfb_init_wsdisplay;
  192 
  193         vcons_init_screen(&dc->dc_vd, &dc->dc_console, 1, &defattr);
  194         dc->dc_console.scr_flags |= VCONS_SCREEN_IS_STATIC;
  195 
  196         aprint_normal("%s: %dMB, %s%dx%d, %dbpp\n",
  197                device_xname(sc->sc_dev),
  198                (uint32_t)(dc->dc_vmemsz >> 20),
  199                (dc->dc_hwflags & IGSFB_HW_BSWAP)
  200                    ? (dc->dc_hwflags & IGSFB_HW_BE_SELECT)
  201                        ? "hardware bswap, " : "software bswap, "
  202                    : "",
  203                dc->dc_width, dc->dc_height, dc->dc_depth);
  204         aprint_normal("%s: using %dbpp for X\n", device_xname(sc->sc_dev),
  205                dc->dc_maxdepth);
  206         ri = &dc->dc_console.scr_ri;
  207         ri->ri_ops.eraserows(ri, 0, ri->ri_rows, defattr);
  208 
  209         if (isconsole)
  210                 vcons_replay_msgbuf(&dc->dc_console);
  211 
  212         /* attach wsdisplay */
  213         waa.console = isconsole;
  214         waa.scrdata = &igsfb_screenlist;
  215         waa.accessops = &igsfb_accessops;
  216         waa.accesscookie = &dc->dc_vd;
  217 
  218         config_found(sc->sc_dev, &waa, wsemuldisplaydevprint, CFARGS_NONE);
  219 }
  220 
  221 
  222 static int
  223 igsfb_init_video(struct igsfb_devconfig *dc)
  224 {
  225         bus_space_handle_t tmph;
  226         uint8_t *p;
  227         int need_bswap;
  228         bus_addr_t fbaddr, craddr;
  229         off_t croffset;
  230         uint8_t busctl, curctl;
  231         void *va;
  232 
  233         /* Total amount of video memory. */
  234         busctl = igs_ext_read(dc->dc_iot, dc->dc_ioh, IGS_EXT_BUS_CTL);
  235         if (busctl & 0x2)
  236                 dc->dc_vmemsz = 4;
  237         else if (busctl & 0x1)
  238                 dc->dc_vmemsz = 2;
  239         else
  240                 dc->dc_vmemsz = 1;
  241         dc->dc_vmemsz <<= 20;   /* megabytes -> bytes */
  242 
  243         /*
  244          * Check for endianness mismatch by writing a word at the end of
  245          * the video memory (off-screen) and reading it back byte-by-byte.
  246          */
  247         if (bus_space_map(dc->dc_memt,
  248                           dc->dc_memaddr + dc->dc_vmemsz - sizeof(uint32_t),
  249                           sizeof(uint32_t),
  250                           dc->dc_memflags | BUS_SPACE_MAP_LINEAR,
  251                           &tmph) != 0)
  252         {
  253                 printf("unable to map video memory for endianness test\n");
  254                 return 1;
  255         }
  256 
  257         p = bus_space_vaddr(dc->dc_memt, tmph);
  258 #if BYTE_ORDER == BIG_ENDIAN
  259         *((uint32_t *)p) = 0x12345678;
  260 #else
  261         *((uint32_t *)p) = 0x78563412;
  262 #endif
  263         if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78)
  264                 need_bswap = 0;
  265         else
  266                 need_bswap = 1;
  267 
  268         bus_space_unmap(dc->dc_memt, tmph, sizeof(uint32_t));
  269 
  270         /*
  271          * On CyberPro we can use magic bswap bit in linear address.
  272          */
  273         fbaddr = dc->dc_memaddr;
  274         if (need_bswap) {
  275                 dc->dc_hwflags |= IGSFB_HW_BSWAP;
  276                 if (dc->dc_id >= 0x2000) {
  277                         dc->dc_hwflags |= IGSFB_HW_BE_SELECT;
  278                         fbaddr |= IGS_MEM_BE_SELECT;
  279                 }
  280         }
  281 
  282         /*
  283          * Map graphic coprocessor for mode setting and accelerated rasops.
  284          */
  285         if (dc->dc_id >= 0x2000) { /* XXX */
  286                 if (bus_space_map(dc->dc_iot,
  287                                   dc->dc_iobase + IGS_COP_BASE_B, IGS_COP_SIZE,
  288                                   dc->dc_ioflags,
  289                                   &dc->dc_coph) != 0)
  290                 {
  291                         printf("unable to map COP registers\n");
  292                         return 1;
  293                 }
  294         }
  295 
  296         igsfb_hw_setup(dc);
  297 
  298         /*
  299          * Don't map in all N megs, just the amount we need for the wsscreen.
  300          */
  301         dc->dc_fbsz = dc->dc_stride * dc->dc_height;
  302         if (bus_space_map(dc->dc_memt, fbaddr, dc->dc_fbsz,
  303                           dc->dc_memflags | BUS_SPACE_MAP_LINEAR,
  304                           &dc->dc_fbh) != 0)
  305         {
  306                 if (dc->dc_id >= 0x2000) { /* XXX */
  307                         bus_space_unmap(dc->dc_iot, dc->dc_coph, IGS_COP_SIZE);
  308                 }
  309                 bus_space_unmap(dc->dc_iot, dc->dc_ioh, IGS_REG_SIZE);
  310                 printf("unable to map framebuffer\n");
  311                 return 1;
  312         }
  313 
  314         igsfb_init_cmap(dc);
  315 
  316         /*
  317          * 1KB for cursor sprite data at the very end of the video memory.
  318          */
  319         croffset = dc->dc_vmemsz - IGS_CURSOR_DATA_SIZE;
  320         craddr = fbaddr + croffset;
  321         if (bus_space_map(dc->dc_memt, craddr, IGS_CURSOR_DATA_SIZE,
  322                           dc->dc_memflags | BUS_SPACE_MAP_LINEAR,
  323                           &dc->dc_crh) != 0)
  324         {
  325                 if (dc->dc_id >= 0x2000) { /* XXX */
  326                         bus_space_unmap(dc->dc_iot, dc->dc_coph, IGS_COP_SIZE);
  327                 }
  328                 bus_space_unmap(dc->dc_iot, dc->dc_ioh, IGS_REG_SIZE);
  329                 bus_space_unmap(dc->dc_memt, dc->dc_fbh, dc->dc_fbsz);
  330                 printf("unable to map cursor sprite region\n");
  331                 return 1;
  332         }
  333 
  334         /*
  335          * Tell the device where cursor sprite data are located in the
  336          * linear space (it takes data offset in 1KB units).
  337          */
  338         croffset >>= 10;        /* bytes -> kilobytes */
  339         igs_ext_write(dc->dc_iot, dc->dc_ioh,
  340                       IGS_EXT_SPRITE_DATA_LO, croffset & 0xff);
  341         igs_ext_write(dc->dc_iot, dc->dc_ioh,
  342                       IGS_EXT_SPRITE_DATA_HI, (croffset >> 8) & 0xf);
  343 
  344         /* init the bit expansion table for cursor sprite data conversion */
  345         igsfb_init_bit_table(dc);
  346 
  347         /* XXX: fill dc_cursor and use igsfb_update_cursor() instead? */
  348         memset(&dc->dc_cursor, 0, sizeof(struct igs_hwcursor));
  349         va = bus_space_vaddr(dc->dc_memt, dc->dc_crh);
  350         memset(va, /* transparent */ 0xaa, IGS_CURSOR_DATA_SIZE);
  351 
  352         curctl = igs_ext_read(dc->dc_iot, dc->dc_ioh, IGS_EXT_SPRITE_CTL);
  353         curctl |= IGS_EXT_SPRITE_64x64;
  354         curctl &= ~IGS_EXT_SPRITE_VISIBLE;
  355         igs_ext_write(dc->dc_iot, dc->dc_ioh, IGS_EXT_SPRITE_CTL, curctl);
  356         dc->dc_curenb = 0;
  357 
  358         /*
  359          * Init graphic coprocessor for accelerated rasops.
  360          */
  361         if (dc->dc_id >= 0x2000) { /* XXX */
  362                 bus_space_write_2(dc->dc_iot, dc->dc_coph,
  363                                   IGS_COP_SRC_MAP_WIDTH_REG,
  364                                   dc->dc_width - 1);
  365                 bus_space_write_2(dc->dc_iot, dc->dc_coph,
  366                                   IGS_COP_DST_MAP_WIDTH_REG,
  367                                   dc->dc_width - 1);
  368 
  369                 bus_space_write_1(dc->dc_iot, dc->dc_coph,
  370                                   IGS_COP_MAP_FMT_REG,
  371                                   howmany(dc->dc_depth, NBBY) - 1);
  372         }
  373 
  374         /* make sure screen is not blanked */
  375         dc->dc_blanked = 0;
  376         igsfb_blank_screen(dc, dc->dc_blanked);
  377 
  378         return 0;
  379 }
  380 
  381 
  382 static void
  383 igsfb_init_cmap(struct igsfb_devconfig *dc)
  384 {
  385         bus_space_tag_t iot = dc->dc_iot;
  386         bus_space_handle_t ioh = dc->dc_ioh;
  387         const uint8_t *p;
  388         int i;
  389 
  390         p = rasops_cmap;        /* "ANSI" color map */
  391 
  392         /* init software copy */
  393         for (i = 0; i < IGS_CMAP_SIZE; ++i, p += 3) {
  394                 dc->dc_cmap.r[i] = p[0];
  395                 dc->dc_cmap.g[i] = p[1];
  396                 dc->dc_cmap.b[i] = p[2];
  397         }
  398 
  399         /* propagate to the device */
  400         igsfb_update_cmap(dc, 0, IGS_CMAP_SIZE);
  401 
  402         /* set overscan color */
  403         p = &rasops_cmap[WSDISPLAY_BORDER_COLOR * 3];
  404         igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_RED,   p[0]);
  405         igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_GREEN, p[1]);
  406         igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_BLUE,  p[2]);
  407 }
  408 
  409 
  410 static void
  411 igsfb_init_wsdisplay(void *cookie, struct vcons_screen *scr, int existing,
  412                      long *defattr)
  413 {
  414         struct igsfb_devconfig *dc = cookie;
  415         struct rasops_info *ri = &scr->scr_ri;
  416         int wsfcookie;
  417 
  418         if (scr == &dc->dc_console) {
  419                 if (ri->ri_flg == 0) {
  420                         /* first time, need to set RI_NO_AUTO */
  421                         ri->ri_flg |= RI_NO_AUTO;
  422                 } else {
  423                         /* clear it on 2nd run */
  424                         ri->ri_flg &= ~RI_NO_AUTO;
  425                 }
  426         }
  427         ri->ri_flg |= RI_CENTER | RI_FULLCLEAR;
  428 
  429         if (IGSFB_HW_SOFT_BSWAP(dc))
  430                 ri->ri_flg |= RI_BSWAP;
  431 
  432         ri->ri_depth = dc->dc_depth;
  433         ri->ri_width = dc->dc_width;
  434         ri->ri_height = dc->dc_height;
  435         ri->ri_stride = dc->dc_stride;
  436         ri->ri_bits = bus_space_vaddr(dc->dc_memt, dc->dc_fbh);
  437 
  438         /*
  439          * Initialize wsfont related stuff.
  440          */
  441         wsfont_init();
  442 
  443         /* prefer gallant that is identical to the one the prom uses */
  444         wsfcookie = wsfont_find("Gallant", 12, 22, 0,
  445                                 WSDISPLAY_FONTORDER_L2R,
  446                                 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
  447         if (wsfcookie <= 0) {
  448 #ifdef DIAGNOSTIC
  449                 printf("unable to find font Gallant 12x22\n");
  450 #endif
  451                 wsfcookie = wsfont_find(NULL, 0, 0, 0, /* any font at all? */
  452                                         WSDISPLAY_FONTORDER_L2R,
  453                                         WSDISPLAY_FONTORDER_L2R,
  454                                         WSFONT_FIND_BITMAP);
  455         }
  456 
  457         if (wsfcookie <= 0) {
  458                 printf("unable to find any fonts\n");
  459                 return;
  460         }
  461 
  462         if (wsfont_lock(wsfcookie, &ri->ri_font) != 0) {
  463                 printf("unable to lock font\n");
  464                 return;
  465         }
  466         ri->ri_wsfcookie = wsfcookie;
  467 
  468 
  469         /* XXX: TODO: compute term size based on font dimensions? */
  470         rasops_init(ri, 0, 0);
  471         rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
  472             ri->ri_width / ri->ri_font->fontwidth);
  473 
  474 
  475         /* use the sprite for the text mode cursor */
  476         igsfb_make_text_cursor(dc, scr);
  477 
  478         /* the cursor is "busy" while we are in the text mode */
  479         dc->dc_hwflags |= IGSFB_HW_TEXT_CURSOR;
  480 
  481         /* propagate sprite data to the device */
  482         igsfb_update_cursor(dc, WSDISPLAY_CURSOR_DOSHAPE);
  483 
  484         /* accelerated text cursor */
  485         ri->ri_ops.cursor = igsfb_accel_cursor;
  486 
  487         if (dc->dc_id >= 0x2000) { /* XXX */
  488                 /* accelerated erase/copy */
  489                 ri->ri_ops.copycols = igsfb_accel_copycols;
  490                 ri->ri_ops.erasecols = igsfb_accel_erasecols;
  491                 ri->ri_ops.copyrows = igsfb_accel_copyrows;
  492                 ri->ri_ops.eraserows = igsfb_accel_eraserows;
  493 
  494                 /* putchar hook to sync with the cop */
  495                 dc->dc_ri_putchar = ri->ri_ops.putchar;
  496                 ri->ri_ops.putchar = igsfb_accel_putchar;
  497         }
  498 
  499         igsfb_stdscreen.nrows = ri->ri_rows;
  500         igsfb_stdscreen.ncols = ri->ri_cols;
  501         igsfb_stdscreen.textops = &ri->ri_ops;
  502         igsfb_stdscreen.capabilities = ri->ri_caps;
  503 }
  504 
  505 
  506 /*
  507  * Init cursor data in dc_cursor for the accelerated text cursor.
  508  */
  509 static int
  510 igsfb_make_text_cursor(struct igsfb_devconfig *dc, struct vcons_screen *scr)
  511 {
  512         struct rasops_info *ri = &scr->scr_ri;
  513         struct wsdisplay_font *f = ri->ri_font;
  514         uint16_t cc_scan[8];    /* one sprite scanline */
  515         uint16_t s;
  516         int w, i;
  517 
  518         KASSERT(f->fontwidth <= IGS_CURSOR_MAX_SIZE);
  519         KASSERT(f->fontheight <= IGS_CURSOR_MAX_SIZE);
  520 
  521         w = f->fontwidth;
  522         for (i = 0; i < f->stride; ++i) {
  523                 if (w >= 8) {
  524                         s = 0xffff; /* all inverted */
  525                         w -= 8;
  526                 } else {
  527                         /* first w pixels inverted, the rest is transparent */
  528                         s = ~(0x5555 << (w * 2));
  529                         s = htole16(s);
  530                         w = 0;
  531                 }
  532                 cc_scan[i] = s;
  533         }
  534 
  535         dc->dc_cursor.cc_size.x = f->fontwidth;
  536         dc->dc_cursor.cc_size.y = f->fontheight;
  537 
  538         dc->dc_cursor.cc_hot.x = 0;
  539         dc->dc_cursor.cc_hot.y = 0;
  540 
  541         /* init sprite array to be all transparent */
  542         memset(dc->dc_cursor.cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE);
  543 
  544         for (i = 0; i < f->fontheight; ++i)
  545                 memcpy(&dc->dc_cursor.cc_sprite[i * 8],
  546                        cc_scan, f->stride * sizeof(uint16_t));
  547 
  548         return 0;
  549 }
  550 
  551 
  552 /*
  553  * Spread a byte (abcd.efgh) into two (0a0b.0c0d 0e0f.0g0h).
  554  * Helper function for igsfb_init_bit_table().
  555  */
  556 static uint16_t
  557 igsfb_spread_bits_8(uint8_t b)
  558 {
  559         uint16_t s = b;
  560 
  561         s = ((s & 0x00f0) << 4) | (s & 0x000f);
  562         s = ((s & 0x0c0c) << 2) | (s & 0x0303);
  563         s = ((s & 0x2222) << 1) | (s & 0x1111);
  564         return s;
  565 }
  566 
  567 
  568 /*
  569  * Cursor sprite data are in 2bpp.  Incoming image/mask are in 1bpp.
  570  * Prebuild the table to expand 1bpp->2bpp, with bswapping if necessary.
  571  */
  572 static void
  573 igsfb_init_bit_table(struct igsfb_devconfig *dc)
  574 {
  575         uint16_t *expand = dc->dc_bexpand;
  576         uint16_t s;
  577         u_int i;
  578 
  579         for (i = 0; i < 256; ++i) {
  580                 s = igsfb_spread_bits_8(i);
  581                 expand[i] = htole16(s);
  582         }
  583 }
  584 
  585 
  586 /*
  587  * wsdisplay_accessops: mmap()
  588  *   XXX: security considerations for allowing mmapping i/o mapped i/o regs?
  589  */
  590 static paddr_t
  591 igsfb_mmap(void *v, void *vs, off_t offset, int prot)
  592 {
  593         struct vcons_data *vd = v;
  594         struct igsfb_devconfig *dc = vd->cookie;
  595 
  596         if (offset < dc->dc_memsz && offset >= 0)
  597                 return bus_space_mmap(dc->dc_memt, dc->dc_memaddr, offset,
  598                     prot, dc->dc_memflags | BUS_SPACE_MAP_LINEAR);
  599         if (dc->dc_mmap)
  600                 return dc->dc_mmap(v, vs, offset, prot);
  601         return -1;
  602 }
  603 
  604 
  605 /*
  606  * wsdisplay_accessops: ioctl()
  607  */
  608 static int
  609 igsfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
  610         struct lwp *l)
  611 {
  612         struct vcons_data *vd = v;
  613         struct igsfb_devconfig *dc = vd->cookie;
  614         int cursor_busy;
  615         int turnoff;
  616 
  617         /* don't permit cursor ioctls if we use sprite for text cursor */
  618         cursor_busy = !dc->dc_mapped
  619                 && (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR);
  620 
  621         switch (cmd) {
  622 
  623         case WSDISPLAYIO_GTYPE:
  624                 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
  625                 return 0;
  626 
  627         case WSDISPLAYIO_GINFO:
  628 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
  629                 wsd_fbip->height = dc->dc_height;
  630                 wsd_fbip->width = dc->dc_width;
  631                 wsd_fbip->depth = dc->dc_maxdepth;
  632                 wsd_fbip->cmsize = IGS_CMAP_SIZE;
  633 #undef wsd_fbip
  634                 return 0;
  635 
  636         case WSDISPLAYIO_LINEBYTES:
  637                 *(int *)data = dc->dc_width * howmany(dc->dc_maxdepth, NBBY);
  638                 return 0;
  639 
  640         case WSDISPLAYIO_SMODE:
  641 #define d (*(int *)data)
  642                 if (d != WSDISPLAYIO_MODE_EMUL) {
  643                         dc->dc_mapped = 1;
  644                         /* turn off hardware cursor */
  645                         if (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR) {
  646                                 dc->dc_curenb = 0;
  647                                 igsfb_update_cursor(dc,
  648                                         WSDISPLAY_CURSOR_DOCUR);
  649                         }
  650                         if ((dc->dc_mode != NULL) && (dc->dc_maxdepth != 8))
  651                                 igsfb_set_mode(dc, dc->dc_mode,
  652                                     dc->dc_maxdepth);
  653                 } else {
  654                         dc->dc_mapped = 0;
  655                         if ((dc->dc_mode != NULL) && (dc->dc_maxdepth != 8))
  656                                 igsfb_set_mode(dc, dc->dc_mode, 8);
  657                         igsfb_init_cmap(dc);
  658                         /* reinit sprite for text cursor */
  659                         if (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR) {
  660                                 igsfb_make_text_cursor(dc, dc->dc_vd.active);
  661                                 dc->dc_curenb = 0;
  662                                 igsfb_update_cursor(dc,
  663                                           WSDISPLAY_CURSOR_DOSHAPE
  664                                         | WSDISPLAY_CURSOR_DOCUR);
  665                         }
  666                         vcons_redraw_screen(vd->active);
  667                 }
  668                 return 0;
  669 
  670         case WSDISPLAYIO_GVIDEO:
  671                 *(u_int *)data = dc->dc_blanked ?
  672                     WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
  673                 return 0;
  674 
  675         case WSDISPLAYIO_SVIDEO:
  676                 turnoff = (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF);
  677                 if (dc->dc_blanked != turnoff) {
  678                         dc->dc_blanked = turnoff;
  679                         igsfb_blank_screen(dc, dc->dc_blanked);
  680                 }
  681                 return 0;
  682 
  683         case WSDISPLAYIO_GETCMAP:
  684                 return igsfb_get_cmap(dc, (struct wsdisplay_cmap *)data);
  685 
  686         case WSDISPLAYIO_PUTCMAP:
  687                 return igsfb_set_cmap(dc, (struct wsdisplay_cmap *)data);
  688 
  689         case WSDISPLAYIO_GCURMAX:
  690                 ((struct wsdisplay_curpos *)data)->x = IGS_CURSOR_MAX_SIZE;
  691                 ((struct wsdisplay_curpos *)data)->y = IGS_CURSOR_MAX_SIZE;
  692                 return 0;
  693 
  694         case WSDISPLAYIO_GCURPOS:
  695                 if (cursor_busy)
  696                         return EBUSY;
  697                 *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos;
  698                 return 0;
  699 
  700         case WSDISPLAYIO_SCURPOS:
  701                 if (cursor_busy)
  702                         return EBUSY;
  703                 igsfb_set_curpos(dc, (struct wsdisplay_curpos *)data);
  704                 return 0;
  705 
  706         case WSDISPLAYIO_GCURSOR:
  707                 if (cursor_busy)
  708                         return EBUSY;
  709                 return igsfb_get_cursor(dc, (struct wsdisplay_cursor *)data);
  710 
  711         case WSDISPLAYIO_SCURSOR:
  712                 if (cursor_busy)
  713                         return EBUSY;
  714                 return igsfb_set_cursor(dc, (struct wsdisplay_cursor *)data);
  715         }
  716 
  717         return EPASSTHROUGH;
  718 }
  719 
  720 
  721 /*
  722  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SVIDEO)
  723  */
  724 static void
  725 igsfb_blank_screen(struct igsfb_devconfig *dc, int blank)
  726 {
  727 
  728         igs_ext_write(dc->dc_iot, dc->dc_ioh,
  729                       IGS_EXT_SYNC_CTL,
  730                       blank ? IGS_EXT_SYNC_H0 | IGS_EXT_SYNC_V0
  731                             : 0);
  732 }
  733 
  734 
  735 /*
  736  * wsdisplay_accessops: ioctl(WSDISPLAYIO_GETCMAP)
  737  *   Served from the software cmap copy.
  738  */
  739 static int
  740 igsfb_get_cmap(struct igsfb_devconfig *dc, struct wsdisplay_cmap *p)
  741 {
  742         u_int index, count;
  743         int err;
  744 
  745         index = p->index;
  746         count = p->count;
  747 
  748         if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index)
  749                 return EINVAL;
  750 
  751         err = copyout(&dc->dc_cmap.r[index], p->red, count);
  752         if (err)
  753                 return err;
  754         err = copyout(&dc->dc_cmap.g[index], p->green, count);
  755         if (err)
  756                 return err;
  757         err = copyout(&dc->dc_cmap.b[index], p->blue, count);
  758         if (err)
  759                 return err;
  760 
  761         return 0;
  762 }
  763 
  764 
  765 /*
  766  * wsdisplay_accessops: ioctl(WSDISPLAYIO_PUTCMAP)
  767  *   Set the software cmap copy and propagate changed range to the device.
  768  */
  769 static int
  770 igsfb_set_cmap(struct igsfb_devconfig *dc, const struct wsdisplay_cmap *p)
  771 {
  772         u_int index, count;
  773         uint8_t r[IGS_CMAP_SIZE];
  774         uint8_t g[IGS_CMAP_SIZE];
  775         uint8_t b[IGS_CMAP_SIZE];
  776         int error;
  777 
  778         index = p->index;
  779         count = p->count;
  780         if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index)
  781                 return EINVAL;
  782         error = copyin(p->red, &r[index], count);
  783         if (error)
  784                 return error;
  785         error = copyin(p->green, &g[index], count);
  786         if (error)
  787                 return error;
  788         error = copyin(p->blue, &b[index], count);
  789         if (error)
  790                 return error;
  791 
  792         memcpy(&dc->dc_cmap.r[index], &r[index], count);
  793         memcpy(&dc->dc_cmap.g[index], &g[index], count);
  794         memcpy(&dc->dc_cmap.b[index], &b[index], count);
  795 
  796         /* propagate changes to the device */
  797         igsfb_update_cmap(dc, index, count);
  798         return 0;
  799 }
  800 
  801 
  802 /*
  803  * Propagate specified part of the software cmap copy to the device.
  804  */
  805 static void
  806 igsfb_update_cmap(struct igsfb_devconfig *dc, u_int index, u_int count)
  807 {
  808         bus_space_tag_t t;
  809         bus_space_handle_t h;
  810         u_int last, i;
  811 
  812         if (index >= IGS_CMAP_SIZE)
  813                 return;
  814 
  815         if (count > IGS_CMAP_SIZE - index)
  816                 last = IGS_CMAP_SIZE;
  817         else
  818                 last = index + count;
  819 
  820         t = dc->dc_iot;
  821         h = dc->dc_ioh;
  822 
  823         /* start palette writing, index is autoincremented by hardware */
  824         bus_space_write_1(t, h, IGS_DAC_PEL_WRITE_IDX, index);
  825 
  826         for (i = index; i < last; ++i) {
  827                 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.r[i]);
  828                 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.g[i]);
  829                 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.b[i]);
  830         }
  831 }
  832 
  833 
  834 /*
  835  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURPOS)
  836  */
  837 static void
  838 igsfb_set_curpos(struct igsfb_devconfig *dc,
  839                  const struct wsdisplay_curpos *curpos)
  840 {
  841         struct rasops_info *ri = &dc->dc_vd.active->scr_ri;
  842         u_int x = curpos->x, y = curpos->y;
  843 
  844         if (x >= ri->ri_width)
  845                 x = ri->ri_width - 1;
  846         if (y >= ri->ri_height)
  847                 y = ri->ri_height - 1;
  848 
  849         dc->dc_cursor.cc_pos.x = x;
  850         dc->dc_cursor.cc_pos.y = y;
  851 
  852         /* propagate changes to the device */
  853         igsfb_update_curpos(dc);
  854 }
  855 
  856 
  857 static void
  858 igsfb_update_curpos(struct igsfb_devconfig *dc)
  859 {
  860         bus_space_tag_t t;
  861         bus_space_handle_t h;
  862         int x, xoff, y, yoff;
  863 
  864         xoff = 0;
  865         x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x;
  866         if (x < 0) {
  867                 xoff = -x;
  868                 x = 0;
  869         }
  870 
  871         yoff = 0;
  872         y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y;
  873         if (y < 0) {
  874                 yoff = -y;
  875                 y = 0;
  876         }
  877 
  878         t = dc->dc_iot;
  879         h = dc->dc_ioh;
  880 
  881         igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_LO, x & 0xff);
  882         igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_HI, (x >> 8) & 0x07);
  883         igs_ext_write(t, h, IGS_EXT_SPRITE_HPRESET, xoff & 0x3f);
  884 
  885         igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_LO, y & 0xff);
  886         igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_HI, (y >> 8) & 0x07);
  887         igs_ext_write(t, h, IGS_EXT_SPRITE_VPRESET, yoff & 0x3f);
  888 }
  889 
  890 
  891 /*
  892  * wsdisplay_accessops: ioctl(WSDISPLAYIO_GCURSOR)
  893  */
  894 static int
  895 igsfb_get_cursor(struct igsfb_devconfig *dc, struct wsdisplay_cursor *p)
  896 {
  897 
  898         /* XXX: TODO */
  899         return 0;
  900 }
  901 
  902 
  903 /*
  904  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURSOR)
  905  */
  906 static int
  907 igsfb_set_cursor(struct igsfb_devconfig *dc, const struct wsdisplay_cursor *p)
  908 {
  909         struct igs_hwcursor *cc;
  910         struct wsdisplay_curpos pos, hot;
  911         u_int v, index, count, icount, iwidth;
  912         uint8_t r[2], g[2], b[2], image[512], mask[512];
  913         int error;
  914 
  915         cc = &dc->dc_cursor;
  916         v = p->which;
  917         index = count = icount = iwidth = 0;    /* XXX: gcc */
  918         pos.x = pos.y = 0;                      /* XXX: gcc */
  919 
  920         /* copy in the new cursor colormap */
  921         if (v & WSDISPLAY_CURSOR_DOCMAP) {
  922                 index = p->cmap.index;
  923                 count = p->cmap.count;
  924                 if (index >= 2 || (index + count) > 2)
  925                         return EINVAL;
  926                 error = copyin(p->cmap.red, &r[index], count);
  927                 if (error)
  928                         return error;
  929                 error = copyin(p->cmap.green, &g[index], count);
  930                 if (error)
  931                         return error;
  932                 error = copyin(p->cmap.blue, &b[index], count);
  933                 if (error)
  934                         return error;
  935         }
  936 
  937         /* verify that the new cursor data are valid */
  938         if (v & WSDISPLAY_CURSOR_DOSHAPE) {
  939                 if (p->size.x > IGS_CURSOR_MAX_SIZE
  940                     || p->size.y > IGS_CURSOR_MAX_SIZE)
  941                         return EINVAL;
  942 
  943                 iwidth = (p->size.x + 7) >> 3; /* bytes per scan line */
  944                 icount = iwidth * p->size.y;
  945                 error = copyin(p->image, image, icount);
  946                 if (error)
  947                         return error;
  948                 error = copyin(p->mask, mask, icount);
  949                 if (error)
  950                         return error;
  951         }
  952 
  953         /* enforce that the position is within screen bounds */
  954         if (v & WSDISPLAY_CURSOR_DOPOS) {
  955                 struct rasops_info *ri = &dc->dc_vd.active->scr_ri;
  956 
  957                 pos = p->pos;   /* local copy we can write to */
  958                 if (pos.x >= ri->ri_width)
  959                         pos.x = ri->ri_width - 1;
  960                 if (pos.y >= ri->ri_height)
  961                         pos.y = ri->ri_height - 1;
  962         }
  963 
  964         /* enforce that the hot spot is within sprite bounds */
  965         if (v & WSDISPLAY_CURSOR_DOHOT)
  966                 hot = p->hot;   /* local copy we can write to */
  967 
  968         if (v & (WSDISPLAY_CURSOR_DOHOT | WSDISPLAY_CURSOR_DOSHAPE)) {
  969                 const struct wsdisplay_curpos *nsize;
  970                 struct wsdisplay_curpos *nhot;
  971 
  972                 nsize = (v & WSDISPLAY_CURSOR_DOSHAPE) ?
  973                             &p->size : &cc->cc_size;
  974                 nhot = (v & WSDISPLAY_CURSOR_DOHOT) ? &hot : &cc->cc_hot;
  975 
  976                 if (nhot->x >= nsize->x)
  977                         nhot->x = nsize->x - 1;
  978                 if (nhot->y >= nsize->y)
  979                         nhot->y = nsize->y - 1;
  980         }
  981 
  982         /* copy data to the driver's cursor info */
  983         if (v & WSDISPLAY_CURSOR_DOCUR)
  984                 dc->dc_curenb = p->enable;
  985         if (v & WSDISPLAY_CURSOR_DOPOS)
  986                 cc->cc_pos = pos; /* local copy, possibly corrected */
  987         if (v & WSDISPLAY_CURSOR_DOHOT)
  988                 cc->cc_hot = hot; /* local copy, possibly corrected */
  989         if (v & WSDISPLAY_CURSOR_DOCMAP) {
  990                 memcpy(&cc->cc_color[index], &r[index], count);
  991                 memcpy(&cc->cc_color[index + 2], &g[index], count);
  992                 memcpy(&cc->cc_color[index + 4], &b[index], count);
  993         }
  994         if (v & WSDISPLAY_CURSOR_DOSHAPE) {
  995                 u_int trailing_bits;
  996 
  997                 memcpy(cc->cc_image, image, icount);
  998                 memcpy(cc->cc_mask, mask, icount);
  999                 cc->cc_size = p->size;
 1000 
 1001                 /* clear trailing bits in the "partial" mask bytes */
 1002                 trailing_bits = p->size.x & 0x07;
 1003                 if (trailing_bits != 0) {
 1004                         const u_int cutmask = ~((~0U) << trailing_bits);
 1005                         u_char *mp;
 1006                         u_int i;
 1007 
 1008                         mp = cc->cc_mask + iwidth - 1;
 1009                         for (i = 0; i < p->size.y; ++i) {
 1010                                 *mp &= cutmask;
 1011                                 mp += iwidth;
 1012                         }
 1013                 }
 1014                 igsfb_convert_cursor_data(dc, iwidth, p->size.y);
 1015         }
 1016 
 1017         /* propagate changes to the device */
 1018         igsfb_update_cursor(dc, v);
 1019 
 1020         return 0;
 1021 }
 1022 
 1023 
 1024 /*
 1025  * Convert incoming 1bpp cursor image/mask into native 2bpp format.
 1026  */
 1027 static void
 1028 igsfb_convert_cursor_data(struct igsfb_devconfig *dc,
 1029                           u_int width, u_int height)
 1030 {
 1031         struct igs_hwcursor *cc = &dc->dc_cursor;
 1032         uint16_t *expand = dc->dc_bexpand;
 1033         uint8_t *ip, *mp;
 1034         uint16_t is, ms, *dp;
 1035         u_int line, i;
 1036 
 1037         /* init sprite to be all transparent */
 1038         memset(cc->cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE);
 1039 
 1040         /* first scanline */
 1041         ip = cc->cc_image;
 1042         mp = cc->cc_mask;
 1043         dp = cc->cc_sprite;
 1044 
 1045         for (line = 0; line < height; ++line) {
 1046                 for (i = 0; i < width; ++i) {
 1047                         is = expand[ip[i]]; /* image: 0 -> 00, 1 -> 01 */
 1048                         ms = expand[mp[i]]; /*  mask: 0 -> 00, 1 -> 11 */
 1049                         ms |= (ms << 1);
 1050                         dp[i] = (0xaaaa & ~ms) | (is & ms);
 1051                 }
 1052 
 1053                 /* next scanline */
 1054                 ip += width;
 1055                 mp += width;
 1056                 dp += 8; /* 64 pixels, 2bpp, 8 pixels per short = 8 shorts */
 1057         }
 1058 }
 1059 
 1060 
 1061 /*
 1062  * Propagate cursor changes to the device.
 1063  * "which" is composed of WSDISPLAY_CURSOR_DO* bits.
 1064  */
 1065 static void
 1066 igsfb_update_cursor(struct igsfb_devconfig *dc, u_int which)
 1067 {
 1068         bus_space_tag_t iot = dc->dc_iot;
 1069         bus_space_handle_t ioh = dc->dc_ioh;
 1070         uint8_t curctl;
 1071 
 1072         curctl = 0;             /* XXX: gcc */
 1073 
 1074         /*
 1075          * We will need to tweak sprite control register for cursor
 1076          * visibility and cursor color map manipulation.
 1077          */
 1078         if (which & (WSDISPLAY_CURSOR_DOCUR | WSDISPLAY_CURSOR_DOCMAP)) {
 1079                 curctl = igs_ext_read(iot, ioh, IGS_EXT_SPRITE_CTL);
 1080         }
 1081 
 1082         if (which & WSDISPLAY_CURSOR_DOSHAPE) {
 1083                 uint8_t *dst = bus_space_vaddr(dc->dc_memt, dc->dc_crh);
 1084 
 1085                 /*
 1086                  * memcpy between spaces of different endianness would
 1087                  * be ... special.  We cannot be sure if memcpy gonna
 1088                  * push data in 4-byte chunks, we can't pre-bswap it,
 1089                  * so do it byte-by-byte to preserve byte ordering.
 1090                  */
 1091                 if (IGSFB_HW_SOFT_BSWAP(dc)) {
 1092                         uint8_t *src = (uint8_t *)dc->dc_cursor.cc_sprite;
 1093                         int i;
 1094 
 1095                         for (i = 0; i < IGS_CURSOR_DATA_SIZE; ++i)
 1096                                 *dst++ = *src++;
 1097                 } else {
 1098                         memcpy(dst, dc->dc_cursor.cc_sprite,
 1099                                IGS_CURSOR_DATA_SIZE);
 1100                 }
 1101         }
 1102 
 1103         if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
 1104                 /* code shared with WSDISPLAYIO_SCURPOS */
 1105                 igsfb_update_curpos(dc);
 1106         }
 1107 
 1108         if (which & WSDISPLAY_CURSOR_DOCMAP) {
 1109                 uint8_t *p;
 1110 
 1111                 /* tell DAC we want access to the cursor palette */
 1112                 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
 1113                               curctl | IGS_EXT_SPRITE_DAC_PEL);
 1114 
 1115                 p = dc->dc_cursor.cc_color;
 1116 
 1117                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 0);
 1118                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[0]);
 1119                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[2]);
 1120                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[4]);
 1121 
 1122                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 1);
 1123                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[1]);
 1124                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[3]);
 1125                 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[5]);
 1126 
 1127                 /* restore access to the normal palette */
 1128                 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, curctl);
 1129         }
 1130 
 1131         if (which & WSDISPLAY_CURSOR_DOCUR) {
 1132                 if ((curctl & IGS_EXT_SPRITE_VISIBLE) == 0
 1133                     && dc->dc_curenb)
 1134                         igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
 1135                                       curctl | IGS_EXT_SPRITE_VISIBLE);
 1136                 else if ((curctl & IGS_EXT_SPRITE_VISIBLE) != 0
 1137                          && !dc->dc_curenb)
 1138                         igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
 1139                                       curctl & ~IGS_EXT_SPRITE_VISIBLE);
 1140         }
 1141 }
 1142 
 1143 
 1144 /*
 1145  * Accelerated text mode cursor that uses hardware sprite.
 1146  */
 1147 static void
 1148 igsfb_accel_cursor(void *cookie, int on, int row, int col)
 1149 {
 1150         struct rasops_info *ri = (struct rasops_info *)cookie;
 1151         struct vcons_screen *scr = ri->ri_hw;
 1152         struct igsfb_devconfig *dc = scr->scr_cookie;
 1153         struct igs_hwcursor *cc = &dc->dc_cursor;
 1154         u_int which;
 1155 
 1156         ri->ri_crow = row;
 1157         ri->ri_ccol = col;
 1158 
 1159         which = 0;
 1160         if (on) {
 1161                 ri->ri_flg |= RI_CURSOR;
 1162 
 1163                 /* only bother to move the cursor if it's visible */
 1164                 cc->cc_pos.x = ri->ri_xorigin
 1165                         + ri->ri_ccol * ri->ri_font->fontwidth;
 1166                 cc->cc_pos.y = ri->ri_yorigin
 1167                         + ri->ri_crow * ri->ri_font->fontheight;
 1168                 which |= WSDISPLAY_CURSOR_DOPOS;
 1169         } else
 1170                 ri->ri_flg &= ~RI_CURSOR;
 1171 
 1172         if (dc->dc_curenb != on) {
 1173                 dc->dc_curenb = on;
 1174                 which |= WSDISPLAY_CURSOR_DOCUR;
 1175         }
 1176 
 1177         /* propagate changes to the device */
 1178         igsfb_update_cursor(dc, which);
 1179 }
 1180 
 1181 
 1182 
 1183 /*
 1184  * Accelerated raster ops that use graphic coprocessor.
 1185  */
 1186 
 1187 static int
 1188 igsfb_accel_wait(struct igsfb_devconfig *dc)
 1189 {
 1190         bus_space_tag_t t = dc->dc_iot;
 1191         bus_space_handle_t h = dc->dc_coph;
 1192         int timo = 100000;
 1193         uint8_t reg;
 1194 
 1195         bus_space_write_1(t, h, IGS_COP_MAP_FMT_REG,
 1196             howmany(dc->dc_depth, NBBY) - 1);
 1197         while (timo--) {
 1198                 reg = bus_space_read_1(t, h, IGS_COP_CTL_REG);
 1199                 if ((reg & IGS_COP_CTL_BUSY) == 0)
 1200                         return 0;
 1201         }
 1202 
 1203         return 1;
 1204 }
 1205 
 1206 
 1207 static void
 1208 igsfb_accel_copy(struct igsfb_devconfig *dc, uint32_t src, uint32_t dst,
 1209                  uint16_t width, uint16_t height)
 1210 {
 1211         bus_space_tag_t t = dc->dc_iot;
 1212         bus_space_handle_t h = dc->dc_coph;
 1213         uint32_t toend;
 1214         uint8_t drawcmd;
 1215 
 1216         drawcmd = IGS_COP_DRAW_ALL;
 1217         if (dst > src) {
 1218                 toend = dc->dc_vd.active->scr_ri.ri_width * (height - 1) + (width - 1);
 1219                 src += toend;
 1220                 dst += toend;
 1221                 drawcmd |= IGS_COP_OCTANT_X_NEG | IGS_COP_OCTANT_Y_NEG;
 1222         }
 1223 
 1224         igsfb_accel_wait(dc);
 1225         bus_space_write_1(t, h, IGS_COP_CTL_REG, 0);
 1226 
 1227         bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S);
 1228 
 1229         bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1);
 1230         bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1);
 1231 
 1232         bus_space_write_4(t, h, IGS_COP_SRC_START_REG, src);
 1233         bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst);
 1234 
 1235         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, drawcmd);
 1236         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG);
 1237         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0);
 1238         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG,
 1239                           IGS_COP_OP_PXBLT | IGS_COP_OP_FG_FROM_SRC);
 1240 }
 1241 
 1242 
 1243 static void
 1244 igsfb_accel_fill(struct igsfb_devconfig *dc, uint32_t color, uint32_t dst,
 1245                  uint16_t width, uint16_t height)
 1246 {
 1247         bus_space_tag_t t = dc->dc_iot;
 1248         bus_space_handle_t h = dc->dc_coph;
 1249 
 1250         igsfb_accel_wait(dc);
 1251         bus_space_write_1(t, h, IGS_COP_CTL_REG, 0);
 1252 
 1253         bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S);
 1254 
 1255         bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1);
 1256         bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1);
 1257 
 1258         bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst);
 1259         bus_space_write_4(t, h, IGS_COP_FG_REG, color);
 1260 
 1261         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, IGS_COP_DRAW_ALL);
 1262         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG);
 1263         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0);
 1264         bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG, IGS_COP_OP_PXBLT);
 1265 }
 1266 
 1267 
 1268 static void
 1269 igsfb_accel_copyrows(void *cookie, int src, int dst, int num)
 1270 {
 1271         struct rasops_info *ri = (struct rasops_info *)cookie;
 1272         struct vcons_screen *scr = ri->ri_hw;
 1273         struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie;
 1274         uint32_t srp, dsp;
 1275         uint16_t width, height;
 1276 
 1277         width = ri->ri_emuwidth;
 1278         height = num * ri->ri_font->fontheight;
 1279 
 1280         srp = ri->ri_xorigin
 1281                 + ri->ri_width * (ri->ri_yorigin
 1282                                   + src * ri->ri_font->fontheight);
 1283         dsp = ri->ri_xorigin
 1284                 + ri->ri_width * (ri->ri_yorigin
 1285                                   + dst * ri->ri_font->fontheight);
 1286 
 1287         igsfb_accel_copy(dc, srp, dsp, width, height);
 1288 }
 1289 
 1290 
 1291 static void
 1292 igsfb_accel_copycols(void *cookie, int row, int src, int dst, int num)
 1293 {
 1294         struct rasops_info *ri = (struct rasops_info *)cookie;
 1295         struct vcons_screen *scr = ri->ri_hw;
 1296         struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie;
 1297         uint32_t rowp, srp, dsp;
 1298         uint16_t width, height;
 1299 
 1300         width = num * ri->ri_font->fontwidth;
 1301         height = ri->ri_font->fontheight;
 1302 
 1303         rowp = ri->ri_xorigin
 1304                 + ri->ri_width * (ri->ri_yorigin
 1305                                   + row * ri->ri_font->fontheight);
 1306 
 1307         srp = rowp + src * ri->ri_font->fontwidth;
 1308         dsp = rowp + dst * ri->ri_font->fontwidth;
 1309 
 1310         igsfb_accel_copy(dc, srp, dsp, width, height);
 1311 }
 1312 
 1313 
 1314 static void
 1315 igsfb_accel_eraserows(void *cookie, int row, int num, long attr)
 1316 {
 1317         struct rasops_info *ri = (struct rasops_info *)cookie;
 1318         struct vcons_screen *scr = ri->ri_hw;
 1319         struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie;
 1320         uint32_t color;
 1321         uint32_t dsp;
 1322         uint16_t width, height;
 1323 
 1324         if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
 1325                 width = ri->ri_width;
 1326                 height = ri->ri_height;
 1327                 dsp = 0;
 1328         } else {
 1329                 width = ri->ri_emuwidth;
 1330                 height = num * ri->ri_font->fontheight;
 1331 
 1332                 dsp = ri->ri_xorigin
 1333                         + ri->ri_width * (ri->ri_yorigin
 1334                                           + row * ri->ri_font->fontheight);
 1335         }
 1336 
 1337         /* XXX: we "know" the encoding that rasops' allocattr uses */
 1338         color = (attr >> 16) & 0xff;
 1339 
 1340         igsfb_accel_fill(dc, color, dsp, width, height);
 1341 }
 1342 
 1343 
 1344 static void
 1345 igsfb_accel_erasecols(void *cookie, int row, int col, int num, long attr)
 1346 {
 1347         struct rasops_info *ri = (struct rasops_info *)cookie;
 1348         struct vcons_screen *scr = ri->ri_hw;
 1349         struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie;
 1350         uint32_t color;
 1351         uint32_t rowp, dsp;
 1352         uint16_t width, height;
 1353 
 1354         width = num * ri->ri_font->fontwidth;
 1355         height = ri->ri_font->fontheight;
 1356 
 1357         rowp = ri->ri_xorigin
 1358                 + ri->ri_width * (ri->ri_yorigin
 1359                                   + row * ri->ri_font->fontheight);
 1360 
 1361         dsp = rowp + col * ri->ri_font->fontwidth;
 1362 
 1363         /* XXX: we "know" the encoding that rasops' allocattr uses */
 1364         color = (attr >> 16) & 0xff;
 1365 
 1366         igsfb_accel_fill(dc, color, dsp, width, height);
 1367 }
 1368 
 1369 
 1370 /*
 1371  * Not really implemented here, but we need to hook into the one
 1372  * supplied by rasops so that we can synchronize with the COP.
 1373  */
 1374 static void
 1375 igsfb_accel_putchar(void *cookie, int row, int col, u_int uc, long attr)
 1376 {
 1377         struct rasops_info *ri = (struct rasops_info *)cookie;
 1378         struct vcons_screen *scr = ri->ri_hw;
 1379         struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie;
 1380 
 1381         igsfb_accel_wait(dc);
 1382         (*dc->dc_ri_putchar)(cookie, row, col, uc, attr);
 1383 }

Cache object: 4d3575074e1bd5141113bfa8eb116eea


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