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

Cache object: c16b74310abc023db91c4a147d2c0f6b


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