root/dev/sbus/vigra.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vigramatch
  2. vigraattach
  3. vigra_ioctl
  4. vigra_alloc_screen
  5. vigra_free_screen
  6. vigra_show_screen
  7. vigra_mmap
  8. vigra_setcolor
  9. vigra_getcmap
  10. vigra_putcmap
  11. vigra_loadcmap_immediate
  12. vigra_loadcmap_deferred
  13. vigra_burner
  14. vigra_intr

    1 /*      $OpenBSD: vigra.c,v 1.10 2006/12/17 22:18:16 miod Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2002, 2003, Miodrag Vallat.
    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  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26  * POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  */
   29 
   30 /*
   31  * Driver for the Vigra VS series of SBus framebuffers.
   32  *
   33  * The VS10, VS11 and VS12 models are supported. VS10-EK is handled by the
   34  * regular cgthree driver.
   35  *
   36  * The monochrome VS14, 16 grays VS15, and color VS18 are not supported.
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/buf.h>
   42 #include <sys/device.h>
   43 #include <sys/ioctl.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mman.h>
   46 #include <sys/tty.h>
   47 #include <sys/conf.h>
   48 
   49 #include <uvm/uvm_extern.h>
   50 
   51 #include <machine/autoconf.h>
   52 #include <machine/bus.h>
   53 #include <machine/pmap.h>
   54 #include <machine/cpu.h>
   55 #include <machine/conf.h>
   56 
   57 #include <dev/wscons/wsconsio.h>
   58 #include <dev/wscons/wsdisplayvar.h>
   59 #include <dev/rasops/rasops.h>
   60 #include <machine/fbvar.h>
   61 
   62 #include <dev/sbus/sbusvar.h>
   63 
   64 /*
   65  * The hardware information below has been gathered through experiments, as
   66  * well as the debug information of the SunOS 4.x vigfb driver.
   67  */
   68 
   69 /*
   70  * Control and status registers
   71  */
   72 
   73 struct csregs {
   74         u_int32_t       sosr;
   75         u_int32_t       g3rr;
   76         u_int32_t       bcr;    /* board control register */
   77         u_int32_t       spr;
   78         u_int32_t       g3sr;   /* ramdac status register */
   79 #define STATUS_INTR     0x0001
   80         u_int32_t       imr;    /* interrupt mode register */
   81         u_int32_t       ewcr;
   82         u_int32_t       ssr;
   83 };
   84 
   85 /*
   86  * G300 layout
   87  */
   88 
   89 struct g300dac {
   90         u_int32_t       cmap[256];
   91         u_int32_t       g3null;
   92         u_int32_t       unused1[32];
   93         u_int32_t       half_sync;
   94         u_int32_t       back_porch;
   95         u_int32_t       display;
   96         u_int32_t       short_display;
   97         u_int32_t       broad_pulse;
   98         u_int32_t       vsync;
   99         u_int32_t       vblank;
  100         u_int32_t       vdisplay;
  101         u_int32_t       line_time;
  102         u_int32_t       tos1;
  103         u_int32_t       mem_init;
  104         u_int32_t       transfer_delay;
  105         u_int32_t       unused2[19];
  106         u_int32_t       mask;
  107         u_int32_t       unused3[31];
  108         u_int32_t       cr;
  109         u_int32_t       unused4[31];
  110         u_int32_t       tos2;
  111         u_int32_t       unused5[31];
  112         u_int32_t       boot_location;
  113 };
  114 
  115 /*
  116  * G335 layout
  117  */
  118 
  119 struct g335dac {
  120         u_int32_t       boot_location;
  121         u_int32_t       unused1[32];
  122         u_int32_t       half_sync;
  123         u_int32_t       back_porch;
  124         u_int32_t       display;
  125         u_int32_t       short_display;
  126         u_int32_t       broad_pulse;
  127         u_int32_t       vsync;
  128         u_int32_t       vpre_equalize;
  129         u_int32_t       vpost_equalize;
  130         u_int32_t       vblank;
  131         u_int32_t       vdisplay;
  132         u_int32_t       line_time;
  133         u_int32_t       tos1;
  134         u_int32_t       mem_init;
  135         u_int32_t       transfer_delay;
  136         u_int32_t       unused2[17];
  137         u_int32_t       mask;
  138         u_int32_t       unused3[31];
  139         u_int32_t       cra;
  140         u_int32_t       unused4[15];
  141         u_int32_t       crb;
  142         u_int32_t       unused5[15];
  143         u_int32_t       tos2;
  144         u_int32_t       unused6[32];
  145         u_int32_t       cursor_palette[3];
  146         u_int32_t       unused7[28];
  147         u_int32_t       checksum[3];
  148         u_int32_t       unused8[4];
  149         u_int32_t       cursor_position;
  150         u_int32_t       unused9[56];
  151         u_int32_t       cmap[256];
  152         u_int32_t       cursor_store[512];
  153 };
  154 
  155 union dac {
  156         struct g300dac  g300;
  157         struct g335dac  g335;
  158 };
  159 
  160 /*
  161  * SBUS register mappings
  162  */
  163 #define VIGRA_REG_RAMDAC        1       /* either G300 or G335 */
  164 #define VIGRA_REG_CSR           2
  165 #define VIGRA_REG_VRAM          3
  166 
  167 #define VIGRA_NREG              4
  168 
  169 union vigracmap {
  170         u_char          cm_map[256][4]; /* 256 R/G/B entries plus pad */
  171         u_int32_t       cm_chip[256];   /* the way the chip gets loaded */
  172 };
  173 
  174 /* per-display variables */
  175 struct vigra_softc {
  176         struct  sunfb sc_sunfb;         /* common base part */
  177         bus_space_tag_t sc_bustag;
  178         bus_addr_t      sc_paddr;
  179         volatile struct csregs *sc_regs;/* control registers */
  180         volatile union dac *sc_ramdac;  /* ramdac registers */
  181         union   vigracmap sc_cmap;      /* current colormap */
  182         int     sc_g300;
  183         void    *sc_ih;
  184         int     sc_nscreens;
  185 };
  186 
  187 int vigra_ioctl(void *, u_long, caddr_t, int, struct proc *);
  188 int vigra_alloc_screen(void *, const struct wsscreen_descr *, void **,
  189     int *, int *, long *);
  190 void vigra_free_screen(void *, void *);
  191 int vigra_show_screen(void *, void *, int, void (*cb)(void *, int, int),
  192     void *);
  193 paddr_t vigra_mmap(void *, off_t, int);
  194 void vigra_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
  195 int vigra_getcmap(union vigracmap *, struct wsdisplay_cmap *, int);
  196 int vigra_putcmap(union vigracmap *, struct wsdisplay_cmap *, int);
  197 void vigra_loadcmap_immediate(struct vigra_softc *, int, int);
  198 static __inline__ void vigra_loadcmap_deferred(struct vigra_softc *,
  199     u_int, u_int);
  200 void vigra_burner(void *, u_int, u_int);
  201 int vigra_intr(void *);
  202 
  203 struct wsdisplay_accessops vigra_accessops = {
  204         vigra_ioctl,
  205         vigra_mmap,
  206         vigra_alloc_screen,
  207         vigra_free_screen,
  208         vigra_show_screen,
  209         NULL,   /* load_font */
  210         NULL,   /* scrollback */
  211         NULL,   /* getchar */
  212         vigra_burner,
  213 };
  214 
  215 int     vigramatch(struct device *, void *, void *);
  216 void    vigraattach(struct device *, struct device *, void *);
  217 
  218 struct cfattach vigra_ca = {
  219         sizeof (struct vigra_softc), vigramatch, vigraattach
  220 };
  221 
  222 struct cfdriver vigra_cd = {
  223         NULL, "vigra", DV_DULL
  224 };
  225 
  226 /*
  227  * Match a supported vigra card.
  228  */
  229 int
  230 vigramatch(struct device *parent, void *vcf, void *aux)
  231 {
  232         struct sbus_attach_args *sa = aux;
  233 
  234         if (strcmp("vs10", sa->sa_name) != 0 &&
  235             strcmp("vs11", sa->sa_name) != 0 &&
  236             strcmp("vs12", sa->sa_name) != 0)
  237                 return (0);
  238 
  239         return (1);
  240 }
  241 
  242 /*
  243  * Attach and initialize a vigra display, as well as a child wsdisplay.
  244  */
  245 void
  246 vigraattach(struct device *parent, struct device *self, void *args)
  247 {
  248         struct vigra_softc *sc = (struct vigra_softc *)self;
  249         struct sbus_attach_args *sa = args;
  250         bus_space_tag_t bt;
  251         bus_space_handle_t bh;
  252         int node, row, isconsole = 0;
  253         char *nam;
  254 
  255         bt = sa->sa_bustag;
  256         node = sa->sa_node;
  257         nam = getpropstring(node, "model");
  258         if (*nam == '\0')
  259                 nam = (char *)sa->sa_name;
  260         printf(": %s", nam);
  261 
  262         isconsole = node == fbnode;
  263 
  264         if (sa->sa_nreg < VIGRA_NREG) {
  265                 printf("\n%s: expected %d registers, got %d",
  266                     self->dv_xname, VIGRA_NREG, sa->sa_nreg);
  267                 return;
  268         }
  269 
  270         /*
  271          * Check whether we are using an G300 or an G335 chip.
  272          * The VS10 and VS12 use the G300, while the VS11 uses a G335.
  273          */
  274         sc->sc_g300 = strncmp(nam, "VIGRA,vs11", strlen("VIGRA,vs11"));
  275 
  276         sc->sc_bustag = bt;
  277         if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_CSR].sbr_slot,
  278             sa->sa_reg[VIGRA_REG_CSR].sbr_offset,
  279             sa->sa_reg[VIGRA_REG_CSR].sbr_size, BUS_SPACE_MAP_LINEAR, 0,
  280             &bh) != 0) {
  281                 printf("\n%s: can't map control registers\n", self->dv_xname);
  282                 return;
  283         }
  284         sc->sc_regs = bus_space_vaddr(bt, bh);
  285         if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_RAMDAC].sbr_slot,
  286             sa->sa_reg[VIGRA_REG_RAMDAC].sbr_offset,
  287             sa->sa_reg[VIGRA_REG_RAMDAC].sbr_size, BUS_SPACE_MAP_LINEAR, 0,
  288             &bh) != 0) {
  289                 printf("\n%s: can't map ramdac registers\n", self->dv_xname);
  290                 return;
  291         }
  292         sc->sc_ramdac = bus_space_vaddr(bt, bh);
  293 
  294         /* enable video */
  295         vigra_burner(sc, 1, 0);
  296 
  297         fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
  298         if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_VRAM].sbr_slot,
  299             sa->sa_reg[VIGRA_REG_VRAM].sbr_offset,
  300             round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
  301             &bh) != 0) {
  302                 printf("\n%s: can't map video memory\n", self->dv_xname);
  303                 return;
  304         }
  305         sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
  306         sc->sc_sunfb.sf_ro.ri_hw = sc;
  307         sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[VIGRA_REG_VRAM].sbr_slot,
  308             sa->sa_reg[VIGRA_REG_VRAM].sbr_offset);
  309 
  310         printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
  311 
  312         if ((sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri,
  313             IPL_TTY, 0, vigra_intr, sc, self->dv_xname)) == NULL) {
  314                 printf("%s: couldn't establish interrupt, pri %d\n",
  315                     self->dv_xname, INTLEV(sa->sa_pri));
  316         }
  317 
  318         /*
  319          * If the framebuffer width is under 1024x768, we will switch from the
  320          * PROM font to the more adequate 8x16 font here.
  321          * However, we need to adjust two things in this case:
  322          * - the display row should be overrided from the current PROM metrics,
  323          *   to prevent us from overwriting the last few lines of text.
  324          * - if the 80x34 screen would make a large margin appear around it,
  325          *   choose to clear the screen rather than keeping old prom output in
  326          *   the margins.
  327          * XXX there should be a rasops "clear margins" feature
  328          *
  329          * Also, in 1280x1024 resolution, the PROM display is not centered
  330          * vertically (why? no other frame buffer does this in such a mode!),
  331          * so be lazy and clear the screen here too anyways...
  332          */
  333         fbwscons_init(&sc->sc_sunfb, isconsole && (sc->sc_sunfb.sf_width != 800
  334             && sc->sc_sunfb.sf_width != 1280) ? 0 : RI_CLEAR);
  335         fbwscons_setcolormap(&sc->sc_sunfb, vigra_setcolor);
  336 
  337         if (isconsole) {
  338                 switch (sc->sc_sunfb.sf_width) {
  339                 case 640:
  340                         row = sc->sc_sunfb.sf_ro.ri_rows - 1;
  341                         break;
  342                 case 800:
  343                 case 1280:
  344                         row = 0;        /* screen has been cleared above */
  345                         break;
  346                 default:
  347                         row = -1;
  348                         break;
  349                 }
  350 
  351                 fbwscons_console_init(&sc->sc_sunfb, row);
  352         }
  353 
  354         fbwscons_attach(&sc->sc_sunfb, &vigra_accessops, isconsole);
  355 }
  356 
  357 int
  358 vigra_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
  359 {
  360         struct vigra_softc *sc = v;
  361         struct wsdisplay_cmap *cm;
  362         struct wsdisplay_fbinfo *wdf;
  363         int error;
  364 
  365         switch (cmd) {
  366         case WSDISPLAYIO_GTYPE:
  367                 *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
  368                 break;
  369         case WSDISPLAYIO_GINFO:
  370                 wdf = (struct wsdisplay_fbinfo *)data;
  371                 wdf->height = sc->sc_sunfb.sf_height;
  372                 wdf->width  = sc->sc_sunfb.sf_width;
  373                 wdf->depth  = sc->sc_sunfb.sf_depth;
  374                 wdf->cmsize = 256;
  375                 break;
  376         case WSDISPLAYIO_LINEBYTES:
  377                 *(u_int *)data = sc->sc_sunfb.sf_linebytes;
  378                 break;
  379 
  380         case WSDISPLAYIO_GETCMAP:
  381                 cm = (struct wsdisplay_cmap *)data;
  382                 error = vigra_getcmap(&sc->sc_cmap, cm, sc->sc_g300);
  383                 if (error)
  384                         return (error);
  385                 break;
  386         case WSDISPLAYIO_PUTCMAP:
  387                 cm = (struct wsdisplay_cmap *)data;
  388                 error = vigra_putcmap(&sc->sc_cmap, cm, sc->sc_g300);
  389                 if (error)
  390                         return (error);
  391                 /* if we can handle interrupts, defer the update */
  392                 if (sc->sc_ih != NULL)
  393                         vigra_loadcmap_deferred(sc, cm->index, cm->count);
  394                 else
  395                         vigra_loadcmap_immediate(sc, cm->index, cm->count);
  396                 break;
  397 
  398         case WSDISPLAYIO_SVIDEO:
  399         case WSDISPLAYIO_GVIDEO:
  400                 break;
  401 
  402         case WSDISPLAYIO_GCURPOS:
  403         case WSDISPLAYIO_SCURPOS:
  404         case WSDISPLAYIO_GCURMAX:
  405         case WSDISPLAYIO_GCURSOR:
  406         case WSDISPLAYIO_SCURSOR:
  407         default:
  408                 return (-1);    /* not supported yet */
  409         }
  410 
  411         return (0);
  412 }
  413 
  414 int
  415 vigra_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
  416     int *curxp, int *curyp, long *attrp)
  417 {
  418         struct vigra_softc *sc = v;
  419 
  420         if (sc->sc_nscreens > 0)
  421                 return (ENOMEM);
  422 
  423         *cookiep = &sc->sc_sunfb.sf_ro;
  424         *curyp = 0;
  425         *curxp = 0;
  426         sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
  427             WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp);
  428         sc->sc_nscreens++;
  429         return (0);
  430 }
  431 
  432 void
  433 vigra_free_screen(void *v, void *cookie)
  434 {
  435         struct vigra_softc *sc = v;
  436 
  437         sc->sc_nscreens--;
  438 }
  439 
  440 int
  441 vigra_show_screen(void *v, void *cookie, int waitok,
  442     void (*cb)(void *, int, int), void *cbarg)
  443 {
  444         return (0);
  445 }
  446 
  447 /*
  448  * Return the address that would map the given device at the given
  449  * offset, allowing for the given protection, or return -1 for error.
  450  */
  451 paddr_t
  452 vigra_mmap(void *v, off_t offset, int prot)
  453 {
  454         struct vigra_softc *sc = v;
  455 
  456         if (offset & PGOFSET)
  457                 return (-1);
  458 
  459         if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
  460                 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
  461                     offset, prot, BUS_SPACE_MAP_LINEAR));
  462         }
  463 
  464         return (-1);
  465 }
  466 
  467 void
  468 vigra_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
  469 {
  470         struct vigra_softc *sc = v;
  471 
  472         if (sc->sc_g300) {
  473                 sc->sc_cmap.cm_map[index][3] = r;
  474                 sc->sc_cmap.cm_map[index][2] = g;
  475                 sc->sc_cmap.cm_map[index][1] = b;
  476         } else {
  477                 sc->sc_cmap.cm_map[index][3] = b;
  478                 sc->sc_cmap.cm_map[index][2] = g;
  479                 sc->sc_cmap.cm_map[index][1] = r;
  480         }
  481         sc->sc_cmap.cm_map[index][0] = 0;       /* no alpha channel */
  482 
  483         vigra_loadcmap_immediate(sc, index, 1);
  484 }
  485 
  486 int
  487 vigra_getcmap(union vigracmap *cm, struct wsdisplay_cmap *rcm, int g300)
  488 {
  489         u_int index = rcm->index, count = rcm->count, i;
  490         int error;
  491 
  492         if (index >= 256 || count > 256 - index)
  493                 return (EINVAL);
  494 
  495         if (g300) {
  496                 for (i = 0; i < count; i++) {
  497                         if ((error = copyout(&cm->cm_map[index + i][3],
  498                             &rcm->red[i], 1)) != 0)
  499                                 return (error);
  500                         if ((error = copyout(&cm->cm_map[index + i][1],
  501                             &rcm->blue[i], 1)) != 0)
  502                                 return (error);
  503                 }
  504         } else {
  505                 for (i = 0; i < count; i++) {
  506                         if ((error = copyout(&cm->cm_map[index + i][1],
  507                             &rcm->red[i], 1)) != 0)
  508                                 return (error);
  509                         if ((error = copyout(&cm->cm_map[index + i][3],
  510                             &rcm->blue[i], 1)) != 0)
  511                                 return (error);
  512                 }
  513         }
  514 
  515         for (i = 0; i < count; i++) {
  516                 if ((error = copyout(&cm->cm_map[index + i][2],
  517                     &rcm->green[i], 1)) != 0)
  518                         return (error);
  519         }
  520         return (0);
  521 }
  522 
  523 int
  524 vigra_putcmap(union vigracmap *cm, struct wsdisplay_cmap *rcm, int g300)
  525 {
  526         u_int index = rcm->index, count = rcm->count, i;
  527         int error;
  528 
  529         if (index >= 256 || count > 256 - index)
  530                 return (EINVAL);
  531 
  532         if (g300) {
  533                 for (i = 0; i < count; i++) {
  534                         if ((error = copyin(&rcm->red[i],
  535                             &cm->cm_map[index + i][3], 1)) != 0)
  536                                 return (error);
  537                         if ((error = copyin(&rcm->blue[i],
  538                             &cm->cm_map[index + i][1], 1)) != 0)
  539                                 return (error);
  540                 }
  541         } else {
  542                 for (i = 0; i < count; i++) {
  543                         if ((error = copyin(&rcm->red[i],
  544                             &cm->cm_map[index + i][1], 1)) != 0)
  545                                 return (error);
  546                         if ((error = copyin(&rcm->blue[i],
  547                             &cm->cm_map[index + i][3], 1)) != 0)
  548                                 return (error);
  549                 }
  550         }
  551 
  552         for (i = 0; i < count; i++) {
  553                 if ((error = copyin(&rcm->green[i],
  554                     &cm->cm_map[index + i][2], 1)) != 0)
  555                         return (error);
  556                 cm->cm_map[index + i][0] = 0;   /* no alpha channel */
  557         }
  558         return (0);
  559 }
  560 
  561 void
  562 vigra_loadcmap_immediate(struct vigra_softc *sc, int start, int ncolors)
  563 {
  564         u_int32_t *colp = &sc->sc_cmap.cm_chip[start];
  565         volatile u_int32_t *lutp;
  566        
  567         if (sc->sc_g300)
  568                 lutp = &(sc->sc_ramdac->g300.cmap[start]);
  569         else
  570                 lutp = &(sc->sc_ramdac->g335.cmap[start]);
  571 
  572         while (--ncolors >= 0)
  573                 *lutp++ = *colp++;
  574 }
  575 
  576 static __inline__ void
  577 vigra_loadcmap_deferred(struct vigra_softc *sc, u_int start, u_int ncolors)
  578 {
  579 
  580         sc->sc_regs->imr = 1;
  581 }
  582 
  583 void
  584 vigra_burner(void *v, u_int on, u_int flags)
  585 {
  586         struct vigra_softc *sc = v;
  587 
  588         if (on) {
  589                 sc->sc_regs->bcr = 0;
  590         } else {
  591                 sc->sc_regs->bcr = 1;
  592         }
  593 }
  594 
  595 int
  596 vigra_intr(void *v)
  597 {
  598         struct vigra_softc *sc = v;
  599 
  600         if (sc->sc_regs->imr == 0 ||
  601             !ISSET(sc->sc_regs->g3sr, STATUS_INTR)) {
  602                 /* Not expecting an interrupt, it's not for us. */
  603                 return (0);
  604         }
  605 
  606         /* Acknowledge the interrupt and disable it. */
  607         sc->sc_regs->imr = 0;
  608 
  609         vigra_loadcmap_immediate(sc, 0, 256);
  610 
  611         return (1);
  612 }

/* [<][>][^][v][top][bottom][index][help] */