1450N/A/*
1450N/A * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
1450N/A */
1450N/A
1450N/A#include <sys/visual_io.h>
1450N/A
1450N/A#if VIS_CONS_REV > 2
1450N/A
1450N/A#include "efb.h"
1450N/A
1450N/A/*
1450N/A * Internal functions
1450N/A */
1450N/Astatic int efb_map_dfb(drm_device_t *);
1450N/Astatic void efb_termemu_display(efb_private_t *,
1450N/A struct efb_vis_draw_data *);
1450N/Astatic void efb_termemu_copy(efb_private_t *, struct vis_conscopy *);
1450N/Astatic void efb_termemu_cursor(efb_private_t *, struct vis_conscursor *);
1450N/Astatic int efb_chk_disp_params(efb_private_t *, struct vis_consdisplay *);
1450N/Astatic int efb_chk_copy_params(efb_private_t *, struct vis_conscopy *);
1450N/Astatic int efb_chk_cursor_params(efb_private_t *, struct vis_conscursor *);
1450N/Astatic void efb_polled_conscursor(struct vis_polledio_arg *,
1450N/A struct vis_conscursor *);
1450N/Astatic void efb_polled_consdisplay(struct vis_polledio_arg *,
1450N/A struct vis_consdisplay *);
1450N/Astatic void efb_polled_conscopy(struct vis_polledio_arg *,
1450N/A struct vis_conscopy *);
1450N/Astatic int efb_invalidate_userctx(efb_private_t *);
1450N/Astatic void efb_restore_kcmap(efb_private_t *);
1450N/Astatic void efb_setup_cmap32(efb_private_t *);
1450N/Astatic void efb_polled_check_power(efb_private_t *);
1450N/A
1450N/A/*
1450N/A * All functions called in polled I/O mode should not have lock
1450N/A * ASSERT, for lock is not available in polled I/O mode. Each
1450N/A * time polled routines (e.g. efb_polled_consdisplay) are called,
1450N/A * efb_in_polledio is set and then PASSERT will just simply succeed.
1450N/A */
1450N/Aint volatile efb_in_polledio = 0;
1450N/Astatic void efb_polledio_enter(void);
1450N/Astatic void efb_polledio_exit(void);
1450N/A
1450N/A#define DFB32ADR(efb_priv, row, col) \
1450N/A ((((uint32_t *)efb_priv->consinfo.dfb + \
1450N/A efb_priv->consinfo.offset)) + \
1450N/A ((row) * efb_priv->consinfo.pitch + (col)))
1450N/A
1450N/A#define DFB8ADR(efb_priv, row, col) \
1450N/A (((uint8_t *)efb_priv->consinfo.dfb) + \
1450N/A efb_priv->consinfo.offset + \
1450N/A ((row) * efb_priv->consinfo.pitch + (col)))
1450N/A
1450N/A
1450N/Aint
1450N/Aefb_map_dfb(drm_device_t *statep)
1450N/A{
1450N/A volatile caddr_t registers;
1450N/A uint32_t offset;
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A static struct ddi_device_acc_attr fbMem = {
1450N/A DDI_DEVICE_ATTR_V0,
1450N/A DDI_STRUCTURE_BE_ACC,
1450N/A DDI_STRICTORDER_ACC
1450N/A };
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A registers = efb_priv->registers;
1450N/A
1450N/A if (efb_priv->consinfo.stream == 0)
1450N/A offset = regr(CRTC_OFFSET);
1450N/A else
1450N/A offset = regr(CRTC2_OFFSET);
1450N/A
1450N/A efb_priv->consinfo.offset = offset;
1450N/A
1450N/A if (ddi_regs_map_setup(statep->dip, 1,
1450N/A (caddr_t *)&efb_priv->consinfo.dfb,
1450N/A 0, 0x8000000, &fbMem,
1450N/A (ddi_acc_handle_t *)&efb_priv->consinfo.dfb_handle)) {
1450N/A cmn_err(CE_WARN, "efb_vis_devinit: efb Unable to map dfb");
1450N/A return (DDI_FAILURE);
1450N/A }
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/Aextern int
1450N/Aefb_vis_devinit(drm_device_t *statep, caddr_t data, int flag)
1450N/A{
1450N/A struct vis_devinit devinit = { 0 };
1450N/A volatile caddr_t registers;
1450N/A int i;
1450N/A drm_device_t *dev = statep;
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A if (!(flag & FKIOCTL)) {
1450N/A return (EPERM);
1450N/A }
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A registers = efb_priv->registers;
1450N/A
1450N/A /*
1450N/A * Read the terminal emulator's change mode callback
1450N/A * address out of the incoming structure
1450N/A */
1450N/A if (ddi_copyin(data, &devinit, sizeof (struct vis_devinit), flag)) {
1450N/A return (EFAULT);
1450N/A }
1450N/A
1450N/A
1450N/A DRM_LOCK();
1450N/A
1450N/A /*
1450N/A * Allocate memory needed by the the kernel console
1450N/A */
1450N/A
1450N/A if (efb_priv->consinfo.bufp == NULL) {
1450N/A efb_priv->consinfo.bufsize = DEFCHAR_SIZE * EFB_MAX_PIXBYTES;
1450N/A efb_priv->consinfo.bufp =
1450N/A kmem_zalloc(efb_priv->consinfo.bufsize, KM_SLEEP);
1450N/A }
1450N/A
1450N/A if (efb_priv->consinfo.polledio == NULL) {
1450N/A efb_priv->consinfo.polledio =
1450N/A kmem_zalloc(sizeof (struct vis_polledio), KM_SLEEP);
1450N/A
1450N/A efb_priv->consinfo.polledio->arg =
1450N/A (struct vis_polledio_arg *)efb_priv;
1450N/A }
1450N/A
1450N/A if (efb_priv->consinfo.csrp == NULL)
1450N/A efb_priv->consinfo.csrp =
1450N/A kmem_alloc(CSRMAX * sizeof (uint32_t), KM_SLEEP);
1450N/A
1450N/A /*
1450N/A * Determine which video stream the console will render on.
1450N/A */
1450N/A switch (efb_priv->primary_stream) {
1450N/A case 0: /* PROM version 1.10 or earlier uses 0 to mean stream 1 */
1450N/A case 1:
1450N/A efb_priv->consinfo.stream = 0;
1450N/A break;
1450N/A case 2:
1450N/A efb_priv->consinfo.stream = 1;
1450N/A break;
1450N/A }
1450N/A
1450N/A
1450N/A /*
1450N/A * Extract the terminal emulator's video mode change notification
1450N/A * callback information from the incoming struct
1450N/A */
1450N/A
1450N/A efb_priv->consinfo.te_modechg_cb = devinit.modechg_cb;
1450N/A efb_priv->consinfo.te_ctx = devinit.modechg_arg;
1450N/A
1450N/A efb_getsize(efb_priv);
1450N/A
1450N/A /*
1450N/A * Describe this driver's configuration for the caller.
1450N/A */
1450N/A
1450N/A devinit.version = VIS_CONS_REV;
1450N/A devinit.width = efb_priv->w[efb_priv->consinfo.stream];
1450N/A devinit.height = efb_priv->h[efb_priv->consinfo.stream];
1450N/A devinit.linebytes = devinit.width *
1450N/A efb_priv->depth[efb_priv->consinfo.stream] / 8;
1450N/A devinit.depth = efb_priv->depth[efb_priv->consinfo.stream];
1450N/A /* color_map ? */
1450N/A devinit.mode = VIS_PIXEL;
1450N/A devinit.polledio = efb_priv->consinfo.polledio;
1450N/A
1450N/A
1450N/A /*
1450N/A * Setup the standalone access (polled mode) entry points
1450N/A * which are also passed back to the terminal emulator.
1450N/A */
1450N/A
1450N/A efb_priv->consinfo.polledio->display = efb_polled_consdisplay;
1450N/A efb_priv->consinfo.polledio->copy = efb_polled_conscopy;
1450N/A efb_priv->consinfo.polledio->cursor = efb_polled_conscursor;
1450N/A
1450N/A /*
1450N/A * Get our view of the console as scribbling pad of memory.
1450N/A * (dumb framebuffer)
1450N/A */
1450N/A if (efb_map_dfb(statep) != DDI_SUCCESS) {
1450N/A DRM_UNLOCK();
1450N/A return (ENOMEM);
1450N/A }
1450N/A
1450N/A /*
1450N/A * Calculate the FULL length of a horizontal line of pixel
1450N/A * memory including both the visible portion and the portion
1450N/A * that extends past the visible boundary on the right.
1450N/A * (The invisible section is where any rounding excess
1450N/A * goes to accomodate to the 64 or 256 byte rounding
1450N/A * requirements of certain device functional block
1450N/A * components).
1450N/A */
1450N/A
1450N/A if (efb_priv->consinfo.stream == 0)
1450N/A efb_priv->consinfo.pitch = regr(CRTC_PITCH) * 8;
1450N/A else
1450N/A efb_priv->consinfo.pitch = regr(CRTC2_PITCH) * 8;
1450N/A
1450N/A /*
1450N/A * Clear colormap update flags so we can do lazy loading
1450N/A */
1450N/A for (i = 0; i < EFB_CMAP_ENTRIES; i++) {
1450N/A efb_priv->cmap_flags[0][i] = 0;
1450N/A efb_priv->cmap_flags[1][i] = 0;
1450N/A }
1450N/A
1450N/A /*
1450N/A * TrueColor 24 _requires_ prepping the DAC properly, although it
1450N/A * isn't documented in the Radeon PDF files (there is a reference
1450N/A * in the Mach64 documents, however).
1450N/A */
1450N/A
1450N/A if (devinit.depth == 32)
1450N/A efb_setup_cmap32(efb_priv);
1450N/A
1450N/A
1450N/A DRM_UNLOCK();
1450N/A
1450N/A /*
1450N/A * Send framebuffer kernel console rendering parameters back to the
1450N/A * terminal emulator
1450N/A */
1450N/A
1450N/A if (ddi_copyout(&devinit, data, sizeof (struct vis_devinit), flag))
1450N/A return (EFAULT);
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A/*
1450N/A * This calls back into the terminal emulator to inform it of
1450N/A * a driver mode change.
1450N/A */
1450N/Aextern void
1450N/Aefb_termemu_callback(drm_device_t *statep)
1450N/A{
1450N/A struct vis_devinit devinit = { 0 };
1450N/A volatile caddr_t registers;
1450N/A int npixels = 8;
1450N/A int surface_cntl;
1450N/A
1450N/A int validated = 0;
1450N/A int ntry = 0;
1450N/A
1450N/A drm_device_t *dev = statep;
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A
1450N/A registers = efb_priv->registers;
1450N/A
1450N/A DRM_LOCK();
1450N/A
1450N/A efb_getsize(efb_priv);
1450N/A
1450N/A /* make sure we have the right stream */
1450N/A while (!validated && ntry < 2) {
1450N/A
1450N/A if (efb_priv->consinfo.stream == 0) {
1450N/A efb_priv->consinfo.pitch =
1450N/A (regr(CRTC_PITCH) & CRTC_PITCH__CRTC_PITCH_MASK)
1450N/A * npixels;
1450N/A efb_priv->consinfo.offset = regr(CRTC_OFFSET);
1450N/A
1450N/A } else {
1450N/A efb_priv->consinfo.pitch =
1450N/A (regr(CRTC2_PITCH) & CRTC_PITCH__CRTC_PITCH_MASK)
1450N/A * npixels;
1450N/A efb_priv->consinfo.offset = regr(CRTC2_OFFSET);
1450N/A }
1450N/A
1450N/A if (efb_priv->consinfo.pitch == 0) {
1450N/A efb_priv->consinfo.stream =
1450N/A (~efb_priv->consinfo.stream) & 0x1;
1450N/A ntry++;
1450N/A } else {
1450N/A validated = 1;
1450N/A }
1450N/A }
1450N/A
1450N/A switch (efb_priv->depth[efb_priv->consinfo.stream]) {
1450N/A case 8:
1450N/A efb_priv->consinfo.bgcolor = 0;
1450N/A break;
1450N/A case 32:
1450N/A efb_setup_cmap32(efb_priv);
1450N/A efb_priv->consinfo.bgcolor = 0xffffffff;
1450N/A break;
1450N/A }
1450N/A
1450N/A efb_priv->setting_videomode = 0;
1450N/A
1450N/A surface_cntl = regr(RADEON_SURFACE_CNTL);
1450N/A if (surface_cntl &
1450N/A (RADEON_NONSURF_AP0_SWP_BIG32 | RADEON_NONSURF_AP1_SWP_BIG32)) {
1450N/A
1450N/A /* 00rrggbb */
1450N/A
1450N/A efb_priv->consinfo.rshift = 16;
1450N/A efb_priv->consinfo.gshift = 8;
1450N/A efb_priv->consinfo.bshift = 0;
1450N/A } else {
1450N/A
1450N/A /* bbggrr00 */
1450N/A
1450N/A efb_priv->consinfo.rshift = 8;
1450N/A efb_priv->consinfo.gshift = 16;
1450N/A efb_priv->consinfo.bshift = 24;
1450N/A }
1450N/A
1450N/A DRM_UNLOCK();
1450N/A
1450N/A if (efb_priv->consinfo.te_modechg_cb != NULL) {
1450N/A
1450N/A DRM_LOCK();
1450N/A
1450N/A devinit.version = VIS_CONS_REV;
1450N/A devinit.mode = VIS_PIXEL;
1450N/A devinit.polledio = efb_priv->consinfo.polledio;
1450N/A devinit.width = efb_priv->w[efb_priv->consinfo.stream];
1450N/A devinit.height = efb_priv->h[efb_priv->consinfo.stream];
1450N/A devinit.depth = efb_priv->depth[efb_priv->consinfo.stream];
1450N/A devinit.linebytes = devinit.width *
1450N/A efb_priv->depth[efb_priv->consinfo.stream] / 8;
1450N/A
1450N/A DRM_UNLOCK();
1450N/A
1450N/A efb_priv->consinfo.te_modechg_cb(efb_priv->consinfo.te_ctx,
1450N/A &devinit);
1450N/A }
1450N/A}
1450N/A
1450N/Aextern int
1450N/Aefb_vis_devfini(drm_device_t *statep, caddr_t data, int flag)
1450N/A{
1450N/A _NOTE(ARGUNUSED(data))
1450N/A
1450N/A drm_device_t *dev = statep;
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A if (!(flag & FKIOCTL))
1450N/A return (EPERM);
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A
1450N/A DRM_LOCK();
1450N/A
1450N/A efb_priv->consinfo.polledio->display = NULL;
1450N/A efb_priv->consinfo.polledio->copy = NULL;
1450N/A efb_priv->consinfo.polledio->cursor = NULL;
1450N/A
1450N/A efb_priv->consinfo.te_modechg_cb = NULL;
1450N/A efb_priv->consinfo.te_ctx = NULL;
1450N/A
1450N/A if (efb_priv->consinfo.polledio != NULL) {
1450N/A kmem_free(efb_priv->consinfo.polledio,
1450N/A sizeof (struct vis_polledio));
1450N/A
1450N/A efb_priv->consinfo.polledio = NULL;
1450N/A }
1450N/A
1450N/A if (efb_priv->consinfo.bufp != NULL) {
1450N/A kmem_free(efb_priv->consinfo.bufp,
1450N/A efb_priv->consinfo.bufsize);
1450N/A
1450N/A efb_priv->consinfo.bufsize = 0;
1450N/A efb_priv->consinfo.bufp = NULL;
1450N/A }
1450N/A
1450N/A if (efb_priv->consinfo.csrp != NULL) {
1450N/A kmem_free(efb_priv->consinfo.csrp,
1450N/A CSRMAX * sizeof (uint32_t));
1450N/A efb_priv->consinfo.csrp = NULL;
1450N/A }
1450N/A
1450N/A efb_priv->consinfo.kcmap_max = 0;
1450N/A
1450N/A DRM_UNLOCK();
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A
1450N/A/*
1450N/A * colormap manipulation entry points -------------------------------------
1450N/A *
1450N/A * For 8-bit a'lazy loading' scheme is used so that only restore cmap entries
1450N/A * that have been flagged as in use by the terminal emulator. The highest
1450N/A * ordered cmap entry that has been accessed since console's VIS_DEVINIT
1450N/A * ioctl was invoked is tracked to optimize colormap restoration for speed.
1450N/A *
1450N/A * For 32-bit depth the DAC must be initialized for linear TrueColor 24 before
1450N/A * the colors will work properly.
1450N/A */
1450N/A
1450N/A
1450N/A/*
1450N/A * Initialize the cmap for the current fb depth
1450N/A */
1450N/Astatic void
1450N/Aefb_setup_cmap32(efb_private_t *efb_priv)
1450N/A{
1450N/A int stream = efb_priv->consinfo.stream;
1450N/A int i;
1450N/A
1450N/A for (i = 0; i < EFB_CMAP_ENTRIES; i++) {
1450N/A efb_priv->colormap[stream][0][i] =
1450N/A efb_priv->colormap[stream][1][i] =
1450N/A efb_priv->colormap[stream][2][i] = (i << 2) | (i >> 6);
1450N/A efb_priv->cmap_flags[stream][i] = 1;
1450N/A }
1450N/A efb_cmap_write(efb_priv, stream);
1450N/A}
1450N/A
1450N/A
1450N/A/*
1450N/A * This function is called to save a copy of the kernel terminal emulator's c
1450N/A * color map when a VIS_PUTCMAP ioctl is issued to the driver.
1450N/A */
1450N/Aextern int
1450N/Aefb_vis_putcmap(drm_device_t *statep, caddr_t data, int flag)
1450N/A{
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A struct vis_cmap *cmap = (struct vis_cmap *)data;
1450N/A int stream;
1450N/A int i;
1450N/A
1450N/A if (!(flag & FKIOCTL))
1450N/A return (EPERM);
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A
1450N/A stream = efb_priv->consinfo.stream;
1450N/A
1450N/A for (i = 0; i < cmap->count; ++i) {
1450N/A
1450N/A efb_priv->consinfo.kcmap[stream][0][cmap->index + i] =
1450N/A (cmap->red[i] << 2) | (cmap->red[i] >> 6);
1450N/A
1450N/A efb_priv->consinfo.kcmap[stream][1][cmap->index + i] =
1450N/A (cmap->green[i] << 2) | (cmap->green[i] >> 6);
1450N/A
1450N/A efb_priv->consinfo.kcmap[stream][2][cmap->index + i] =
1450N/A (cmap->blue[i] << 2) | (cmap->blue[i] >> 6);
1450N/A }
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A/*
1450N/A * Re-establish the kernel's 8-bit color map.
1450N/A */
1450N/Astatic void
1450N/Aefb_restore_kcmap(efb_private_t *efb_priv)
1450N/A{
1450N/A int stream, save;
1450N/A int i;
1450N/A
1450N/A stream = efb_priv->consinfo.stream;
1450N/A save = stream + 2;
1450N/A
1450N/A switch (efb_priv->depth[stream]) {
1450N/A case 8:
1450N/A for (i = 0; i <= efb_priv->consinfo.kcmap_max; i++) {
1450N/A
1450N/A if (efb_priv->consinfo.kcmap_flags[stream][i]) {
1450N/A
1450N/A efb_priv->colormap[save][0][i] =
1450N/A efb_priv->colormap[stream][0][i];
1450N/A
1450N/A efb_priv->colormap[save][1][i] =
1450N/A efb_priv->colormap[stream][1][i];
1450N/A
1450N/A efb_priv->colormap[save][2][i] =
1450N/A efb_priv->colormap[stream][2][i];
1450N/A
1450N/A
1450N/A efb_priv->colormap[stream][0][i] =
1450N/A efb_priv->consinfo.kcmap[stream][0][i];
1450N/A
1450N/A efb_priv->colormap[stream][1][i] =
1450N/A efb_priv->consinfo.kcmap[stream][1][i];
1450N/A
1450N/A efb_priv->colormap[stream][2][i] =
1450N/A efb_priv->consinfo.kcmap[stream][2][i];
1450N/A
1450N/A efb_priv->cmap_flags[stream][i] = 1;
1450N/A }
1450N/A }
1450N/A
1450N/A efb_cmap_write(efb_priv, stream);
1450N/A break;
1450N/A
1450N/A case 32:
1450N/A /*
1450N/A * This is a quick chance to see if we've set up the colormap
1450N/A * properly. It is executed for each character so we want to
1450N/A * keep it optimized. It seems to work. Worst case, some
1450N/A * sort of sparse but more thorough checking could be done.
1450N/A * This seems to work for the simple tradeoff between the
1450N/A * X server's colormaps and the kernel terminal emulator's.
1450N/A */
1450N/A if (efb_priv->colormap[stream][0][0] != 0 ||
1450N/A efb_priv->colormap[stream][0][255] != 0x3ff)
1450N/A efb_setup_cmap32(efb_priv);
1450N/A
1450N/A break;
1450N/A }
1450N/A}
1450N/A
1450N/A/*
1450N/A * ioctl entry points -------------------------------------------------
1450N/A *
1450N/A * The ioctl interface tactics differ from the polled interface's.
1450N/A * The console ioctls need to do context management (ie. unload user mappings,
1450N/A * save user context, load kernel's context). However since the kernel's
1450N/A * context isn't associated with memory mappings, the DDI won't prod us to
1450N/A * re-establish the kernel's context if userland interrupts us. Therefore,
1450N/A * we prevent interruption for the duration of any given rendering operation
1450N/A * (ie. displaying character, scrolling one line, or displaying cursor),
1450N/A * by holding the context lock.
1450N/A *
1450N/A * Each rendering operation depends on a particular static setup of the mach64
1450N/A * draw engine state. Besides that, anything the kernel console rendering
1450N/A * functions change in the draw engine state can be discarded, because they
1450N/A * are re-initialized at each rendering operation. Therefore the static
1450N/A * state is saved once when the kernel context is created, and then loaded,
1450N/A * but not saved thereafter.
1450N/A *
1450N/A */
1450N/Aextern int
1450N/Aefb_vis_consdisplay(drm_device_t *statep, caddr_t data, int flag)
1450N/A{
1450N/A struct vis_consdisplay efb_cd;
1450N/A struct efb_vis_draw_data efb_draw;
1450N/A uint32_t image_size;
1450N/A
1450N/A drm_device_t *dev = statep;
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A
1450N/A if (!(flag & FKIOCTL))
1450N/A return (EPERM);
1450N/A
1450N/A if (ddi_copyin(data, &efb_cd, sizeof (struct vis_consdisplay), flag))
1450N/A return (EFAULT);
1450N/A
1450N/A image_size = efb_cd.width * efb_cd.height * EFB_MAX_PIXBYTES;
1450N/A
1450N/A if (image_size > efb_priv->consinfo.bufsize) {
1450N/A void *tmp = efb_priv->consinfo.bufp;
1450N/A if (!(efb_priv->consinfo.bufp =
1450N/A kmem_alloc(image_size, KM_SLEEP))) {
1450N/A efb_priv->consinfo.bufp = tmp;
1450N/A return (ENOMEM);
1450N/A }
1450N/A if (tmp)
1450N/A kmem_free(tmp, efb_priv->consinfo.bufsize);
1450N/A
1450N/A efb_priv->consinfo.bufsize = image_size;
1450N/A }
1450N/A
1450N/A if (ddi_copyin(efb_cd.data, efb_priv->consinfo.bufp,
1450N/A image_size, flag))
1450N/A return (EFAULT);
1450N/A
1450N/A if (efb_chk_disp_params(efb_priv, &efb_cd) != DDI_SUCCESS) {
1450N/A return (EINVAL);
1450N/A }
1450N/A
1450N/A DRM_LOCK();
1450N/A
1450N/A /* Just return if videomode change is on-going */
1450N/A if (efb_priv->setting_videomode) {
1450N/A DRM_UNLOCK();
1450N/A return (DDI_SUCCESS);
1450N/A }
1450N/A
1450N/A efb_draw.image_row = efb_cd.row;
1450N/A efb_draw.image_col = efb_cd.col;
1450N/A efb_draw.image_width = efb_cd.width;
1450N/A efb_draw.image_height = efb_cd.height;
1450N/A efb_draw.image = efb_priv->consinfo.bufp;
1450N/A
1450N/A if (efb_invalidate_userctx(efb_priv) == DDI_SUCCESS) {
1450N/A efb_restore_kcmap(efb_priv);
1450N/A efb_termemu_display(efb_priv, &efb_draw);
1450N/A }
1450N/A
1450N/A DRM_UNLOCK();
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/Aextern int
1450N/Aefb_vis_conscopy(drm_device_t *statep, caddr_t data, int flag)
1450N/A{
1450N/A struct vis_conscopy efb_cpydata;
1450N/A
1450N/A drm_device_t *dev = statep;
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A
1450N/A if (!(flag & FKIOCTL))
1450N/A return (EPERM);
1450N/A
1450N/A if (ddi_copyin(data, &efb_cpydata,
1450N/A sizeof (struct vis_conscopy), flag))
1450N/A return (EFAULT);
1450N/A
1450N/A if (efb_chk_copy_params(efb_priv, &efb_cpydata) != DDI_SUCCESS) {
1450N/A return (EINVAL);
1450N/A }
1450N/A
1450N/A DRM_LOCK();
1450N/A
1450N/A /* Just return if videomode change is on-going */
1450N/A if (efb_priv->setting_videomode) {
1450N/A DRM_UNLOCK();
1450N/A return (DDI_SUCCESS);
1450N/A }
1450N/A
1450N/A if (efb_invalidate_userctx(efb_priv) == DDI_SUCCESS)
1450N/A efb_termemu_copy(efb_priv, &efb_cpydata);
1450N/A
1450N/A DRM_UNLOCK();
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/Aextern int
1450N/Aefb_vis_conscursor(drm_device_t *statep, caddr_t data, int flag)
1450N/A{
1450N/A static struct vis_conscursor efb_cc;
1450N/A
1450N/A drm_device_t *dev = statep;
1450N/A drm_radeon_private_t *dev_priv;
1450N/A efb_private_t *efb_priv;
1450N/A
1450N/A dev_priv = (drm_radeon_private_t *)(statep->dev_private);
1450N/A efb_priv = (efb_private_t *)(dev_priv->private_data);
1450N/A
1450N/A if (!(flag & FKIOCTL))
1450N/A return (EPERM);
1450N/A
1450N/A if (ddi_copyin(data, &efb_cc,
1450N/A sizeof (struct vis_conscursor), flag))
1450N/A return (EFAULT);
1450N/A
1450N/A if (efb_chk_cursor_params(efb_priv, &efb_cc) != DDI_SUCCESS) {
1450N/A return (EINVAL);
1450N/A }
1450N/A
1450N/A DRM_LOCK();
1450N/A
1450N/A /* Just return if videomode change is on-going */
1450N/A if (efb_priv->setting_videomode) {
1450N/A DRM_UNLOCK();
1450N/A return (DDI_SUCCESS);
1450N/A }
1450N/A
1450N/A if (efb_invalidate_userctx(efb_priv) == DDI_SUCCESS)
1450N/A efb_termemu_cursor(efb_priv, &efb_cc);
1450N/A
1450N/A DRM_UNLOCK();
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A/*
1450N/A * Polled I/O Entry Points. -----------------------------------------
1450N/A *
1450N/A * The tactics in these routines are based on the fact that we are
1450N/A * -only- called in standalone mode. Therefore time is frozen
1450N/A * for us. We sneak in restore the kernel's colormap, establish
1450N/A * the kernel's draw engine context, render, and then replace the
1450N/A * previous context -- no one the wiser for it.
1450N/A *
1450N/A * In polled I/O mode (also called standalone mode), the kernel isn't
1450N/A * running, Only one CPU is enabled, system services are not running,
1450N/A * and all access is single-threaded. The limitations of standalone
1450N/A * mode are: (1) The driver cannot wait for interrupts, (2) The driver
1450N/A * cannot use mutexes, (3) The driver cannot allocate memory.
1450N/A *
1450N/A * The advantage of polled I/O mode is, that because we don't have to
1450N/A * worry about concurrent access to device state, we don't need to
1450N/A * unload mappings and can perform a lighter form of graphics context
1450N/A * switching, which doesn't require the use of mutexes.
1450N/A *
1450N/A */
1450N/A
1450N/A
1450N/A/*
1450N/A * Setup for DFB rectangle BLIT on a "quiesced" system
1450N/A */
1450N/Astatic void
1450N/Aefb_polled_consdisplay(struct vis_polledio_arg *arg,
1450N/A struct vis_consdisplay *efb_cd)
1450N/A{
1450N/A efb_private_t *efb_priv = (efb_private_t *)arg;
1450N/A struct efb_vis_draw_data efb_draw;
1450N/A
1450N/A efb_draw.image_row = efb_cd->row;
1450N/A efb_draw.image_col = efb_cd->col;
1450N/A efb_draw.image_width = efb_cd->width;
1450N/A efb_draw.image_height = efb_cd->height;
1450N/A efb_draw.image = efb_cd->data;
1450N/A
1450N/A efb_polledio_enter();
1450N/A efb_polled_check_power(efb_priv);
1450N/A efb_restore_kcmap(efb_priv);
1450N/A efb_termemu_display(efb_priv, &efb_draw);
1450N/A efb_polledio_exit();
1450N/A}
1450N/A
1450N/A/*
1450N/A * Setup for DFB rectangle copy (vertical scroll) on
1450N/A * a "quiesced: system.
1450N/A */
1450N/Astatic void
1450N/Aefb_polled_conscopy(struct vis_polledio_arg *arg,
1450N/A struct vis_conscopy *efb_cpydata)
1450N/A{
1450N/A efb_private_t *efb_priv = (efb_private_t *)arg;
1450N/A
1450N/A efb_polledio_enter();
1450N/A efb_polled_check_power(efb_priv);
1450N/A efb_restore_kcmap(efb_priv);
1450N/A efb_termemu_copy(efb_priv, efb_cpydata);
1450N/A efb_polledio_exit();
1450N/A}
1450N/A
1450N/A
1450N/A/*
1450N/A * Setup for DFB inverting rectangle BLIT (cursor)
1450N/A * on a "quiesced" system.
1450N/A *
1450N/A */
1450N/Astatic void
1450N/Aefb_polled_conscursor(struct vis_polledio_arg *arg,
1450N/A struct vis_conscursor *efb_cc)
1450N/A{
1450N/A efb_private_t *efb_priv = (efb_private_t *)arg;
1450N/A
1450N/A efb_polledio_enter();
1450N/A efb_polled_check_power(efb_priv);
1450N/A efb_restore_kcmap(efb_priv);
1450N/A efb_termemu_cursor(efb_priv, efb_cc);
1450N/A efb_polledio_exit();
1450N/A}
1450N/A
1450N/A/* ----------------------------------------------------------- */
1450N/A
1450N/A/*
1450N/A * Copy to DFB a rectangular image whose size, coordinates and pixels
1450N/A * are defined in the draw struct. The proper pixel conversions
1450N/A * are made based on the video mode depth. This operation is implemented
1450N/A * in terms of memory copies.
1450N/A */
1450N/A
1450N/Astatic void
1450N/Aefb_termemu_display(efb_private_t *efb_priv, struct efb_vis_draw_data *efb_draw)
1450N/A{
1450N/A uint8_t b, *disp, red, grn, blu;
1450N/A void *pixp;
1450N/A int r, c, y, x, h, w;
1450N/A int stream = efb_priv->consinfo.stream;
1450N/A uint32_t pix;
1450N/A int rshift, gshift, bshift;
1450N/A
1450N/A r = efb_draw->image_row;
1450N/A c = efb_draw->image_col;
1450N/A h = efb_draw->image_height;
1450N/A w = efb_draw->image_width;
1450N/A
1450N/A disp = efb_draw->image;
1450N/A
1450N/A rshift = efb_priv->consinfo.rshift;
1450N/A gshift = efb_priv->consinfo.gshift;
1450N/A bshift = efb_priv->consinfo.bshift;
1450N/A
1450N/A for (y = 0; y < h; y++) {
1450N/A
1450N/A for (x = 0; x < w; x++) {
1450N/A
1450N/A switch (efb_priv->depth[stream]) {
1450N/A
1450N/A case 32:
1450N/A /* disp is 00rrggbb */
1450N/A disp++;
1450N/A red = *disp++;
1450N/A grn = *disp++;
1450N/A blu = *disp++;
1450N/A
1450N/A /* Transform into DFB byte order */
1450N/A pix = (red << rshift) | (grn << gshift) |
1450N/A (blu << bshift);
1450N/A pixp = DFB32ADR(efb_priv, r + y, c + x);
1450N/A *(uint32_t *)pixp = pix;
1450N/A break;
1450N/A
1450N/A case 8: /* 8-bit color map index */
1450N/A pixp = DFB8ADR(efb_priv, r + y, c + x);
1450N/A
1450N/A b = *disp++;
1450N/A if (b > efb_priv->consinfo.kcmap_max)
1450N/A efb_priv->consinfo.kcmap_max = b;
1450N/A
1450N/A *(uint8_t *)pixp = b;
1450N/A efb_priv->consinfo.kcmap_flags[stream][b] = 1;
1450N/A break;
1450N/A }
1450N/A }
1450N/A }
1450N/A}
1450N/A
1450N/A/*
1450N/A * This function implements show/hide cursor functions as appropriate
1450N/A * for the current screen depth. Due to the difficulty of managing
1450N/A * a cursor with the multitude of foreground/background text colors,
1450N/A * and framebuffer depths with simple ALU operations, particularly
1450N/A * in 8-bit psuedocolor mode, the cursor is always displayed along
1450N/A * with the underlying pixels in monochrome (ie. black/white). That
1450N/A * retains good legibility for all ANSI fg and bg combinations.
1450N/A * in all depths.
1450N/A *
1450N/A * This approach requires saving the contents under the cursor so
1450N/A * they can be restored when the cursor moves by re-blitting them
1450N/A * onto the DFB, rather than using a heuristic.
1450N/A *
1450N/A * For the SHOW_CURSOR operation, the contents beneath the cursor
1450N/A * are saved before displaying the monochrome overlay in anticipation
1450N/A * of a HIDE_CURSOR operation over the same location, prior to moving
1450N/A * the cursor to a new location.
1450N/A *
1450N/A * The HIDE_CURSOR function simply replaces the text saved under
1450N/A * the cursor rectangle during the previous SHOW_CURSOR operation.
1450N/A *
1450N/A * This protocol necessitates tight cursor protocol agreement
1450N/A * with the terminal emulator.
1450N/A *
1450N/A */
1450N/A
1450N/A#define MASK24(u32) (u32)
1450N/A
1450N/Astatic void
1450N/Aefb_termemu_cursor_32(efb_private_t *efb_priv, struct vis_conscursor *efb_cc)
1450N/A{
1450N/A int x, y;
1450N/A int r = efb_cc->row;
1450N/A int c = efb_cc->col;
1450N/A int w = efb_cc->width;
1450N/A int h = efb_cc->height;
1450N/A
1450N/A uint32_t *pixp;
1450N/A uint32_t *csrp = (uint32_t *)efb_priv->consinfo.csrp;
1450N/A uint32_t rshift = efb_priv->consinfo.rshift;
1450N/A uint32_t gshift = efb_priv->consinfo.gshift;
1450N/A uint32_t bshift = efb_priv->consinfo.bshift;
1450N/A uint32_t fg, bg;
1450N/A
1450N/A ASSERT(efb_priv->depth[efb_priv->consinfo.stream] == 32);
1450N/A
1450N/A /*
1450N/A * Convert fg/bg into DFB order for direct comparability
1450N/A */
1450N/A fg = (efb_cc->fg_color.twentyfour[0] << rshift) |
1450N/A (efb_cc->fg_color.twentyfour[1] << gshift) |
1450N/A (efb_cc->fg_color.twentyfour[2] << bshift);
1450N/A
1450N/A bg = (efb_cc->bg_color.twentyfour[0] << rshift) |
1450N/A (efb_cc->bg_color.twentyfour[1] << gshift) |
1450N/A (efb_cc->bg_color.twentyfour[2] << bshift);
1450N/A
1450N/A if (efb_cc->action == SHOW_CURSOR) {
1450N/A for (y = 0; y < h; y++) {
1450N/A for (x = 0; x < w; x++) {
1450N/A pixp = DFB32ADR(efb_priv, r + y, c + x);
1450N/A csrp[(y * w + x) % CSRMAX] = *pixp;
1450N/A *pixp = (MASK24(*pixp) == MASK24(bg)) ? fg : bg;
1450N/A }
1450N/A }
1450N/A } else {
1450N/A for (y = 0; y < h; y++) {
1450N/A for (x = 0; x < w; x++) {
1450N/A pixp = DFB32ADR(efb_priv, r + y, c + x);
1450N/A *pixp = csrp[(y * w + x) % CSRMAX];
1450N/A }
1450N/A }
1450N/A }
1450N/A}
1450N/A
1450N/Astatic void
1450N/Aefb_termemu_cursor_8(efb_private_t *efb_priv, struct vis_conscursor *efb_cc)
1450N/A{
1450N/A int x, y;
1450N/A int r = efb_cc->row;
1450N/A int c = efb_cc->col;
1450N/A int w = efb_cc->width;
1450N/A int h = efb_cc->height;
1450N/A uint8_t *pixp;
1450N/A uint8_t *csrp = (uint8_t *)efb_priv->consinfo.csrp;
1450N/A
1450N/A uint8_t fg = efb_cc->fg_color.eight;
1450N/A uint8_t bg = efb_cc->bg_color.eight;
1450N/A
1450N/A ASSERT(efb_priv->depth[efb_priv->consinfo.stream] == 8);
1450N/A
1450N/A if (efb_cc->action == SHOW_CURSOR) {
1450N/A for (y = 0; y < h; y++) {
1450N/A for (x = 0; x < w; x++) {
1450N/A pixp = DFB8ADR(efb_priv, r + y, c + x);
1450N/A csrp[(y * w + x) % CSRMAX] = *pixp;
1450N/A *pixp = (*pixp == bg) ? fg : bg;
1450N/A }
1450N/A }
1450N/A } else {
1450N/A for (y = 0; y < h; y++) {
1450N/A for (x = 0; x < w; x++) {
1450N/A pixp = DFB8ADR(efb_priv, r + y, c + x);
1450N/A *pixp = csrp[(y * w + x) % CSRMAX];
1450N/A }
1450N/A }
1450N/A }
1450N/A}
1450N/A
1450N/Astatic void
1450N/Aefb_termemu_cursor(efb_private_t *efb_priv, struct vis_conscursor *efb_cc)
1450N/A{
1450N/A switch (efb_priv->depth[efb_priv->consinfo.stream]) {
1450N/A case 32:
1450N/A efb_termemu_cursor_32(efb_priv, efb_cc);
1450N/A break;
1450N/A case 8:
1450N/A efb_termemu_cursor_8(efb_priv, efb_cc);
1450N/A break;
1450N/A }
1450N/A}
1450N/A
1450N/A/*
1450N/A * This function implements scrolling by copying a rectangular block of
1450N/A * pixels upward on the Y-axis. The caller provides block copy parameters
1450N/A * as a rectangle, defined by (s_col, s_row), (e_col, e_row) and target
1450N/A * coords (t_col, t_row).
1450N/A *
1450N/A * This implementation uses the Radeon GUI engine to accomplish this faster
1450N/A * than memory moves done from software. It is left to the caller to
1450N/A * establish the kernel's graphic context prior to calling this function.
1450N/A */
1450N/Astatic void
1450N/Aefb_termemu_copy(efb_private_t *efb_priv, struct vis_conscopy *efb_copydata)
1450N/A{
1450N/A volatile caddr_t registers = efb_priv->registers;
1450N/A
1450N/A uint16_t srcx = efb_copydata->s_col;
1450N/A uint16_t srcy = efb_copydata->s_row;
1450N/A uint16_t dstx = efb_copydata->t_col;
1450N/A uint16_t dsty = efb_copydata->t_row;
1450N/A uint16_t height = (efb_copydata->e_row - efb_copydata->s_row) + 1;
1450N/A uint16_t width = (efb_copydata->e_col - efb_copydata->s_col) + 1;
1450N/A uint32_t direction = DST_Y_BOTTOM_TO_TOP | DST_X_RIGHT_TO_LEFT;
1450N/A uint32_t gmc_bpp, dp_datatype, pitch_offset;
1450N/A uint32_t depth, pitch, offset;
1450N/A int stream = efb_priv->consinfo.stream;
1450N/A int i;
1450N/A
1450N/A if (srcy < dsty) {
1450N/A dsty += height - 1;
1450N/A srcy += height - 1;
1450N/A } else
1450N/A direction |= DST_Y_TOP_TO_BOTTOM;
1450N/A
1450N/A if (srcx < dstx) {
1450N/A dstx += width - 1;
1450N/A srcx += width - 1;
1450N/A } else
1450N/A direction |= DST_X_LEFT_TO_RIGHT;
1450N/A
1450N/A depth = efb_priv->depth[stream];
1450N/A pitch = efb_priv->consinfo.pitch * depth / 8 / 64;
1450N/A offset = efb_priv->consinfo.offset / 1024;
1450N/A
1450N/A pitch_offset = pitch << DEFAULT_PITCH_OFFSET__DEFAULT_PITCH__SHIFT |
1450N/A offset;
1450N/A
1450N/A switch (depth) {
1450N/A case 8:
1450N/A gmc_bpp = RADEON_GMC_DST_8BPP;
1450N/A dp_datatype = DST_8BPP | BRUSH_SOLIDCOLOR | SRC_DSTCOLOR;
1450N/A break;
1450N/A case 32:
1450N/A gmc_bpp = RADEON_GMC_DST_32BPP;
1450N/A dp_datatype = DST_32BPP | BRUSH_SOLIDCOLOR | SRC_DSTCOLOR;
1450N/A }
1450N/A
1450N/A /*
1450N/A * Initialize GUI engine
1450N/A */
1450N/A (void) efb_wait_idle(efb_priv, "termemu_copy", __LINE__);
1450N/A
1450N/A regw(DEFAULT_PITCH_OFFSET, pitch_offset);
1450N/A regw(RADEON_DST_PITCH_OFFSET, pitch_offset);
1450N/A regw(RADEON_SRC_PITCH_OFFSET, pitch_offset);
1450N/A
1450N/A regw(DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff);
1450N/A
1450N/A regw(RADEON_DP_GUI_MASTER_CNTL,
1450N/A GMC_BRUSH_SOLIDCOLOR |
1450N/A gmc_bpp |
1450N/A GMC_SRC_DSTCOLOR |
1450N/A ROP3_SRCCOPY |
1450N/A GMC_DP_SRC_RECT |
1450N/A GMC_DST_CLR_CMP_FCN_CLEAR |
1450N/A GMC_WRITE_MASK_LEAVE);
1450N/A
1450N/A regw(DST_LINE_START, 0);
1450N/A regw(DST_LINE_END, 0);
1450N/A regw(RB3D_CNTL, 0);
1450N/A regw(DP_WRITE_MSK, 0xffffffff);
1450N/A
1450N/A /*
1450N/A * Switch access mode to PIO
1450N/A */
1450N/A (void) efb_wait_idle(efb_priv, "termemu_copy", __LINE__);
1450N/A regw(DSTCACHE_CTLSTAT, 0xf);
1450N/A for (i = 0;
1450N/A (regr(DSTCACHE_CTLSTAT) & RADEON_RB2D_DC_BUSY) && (i < 16384);
1450N/A i++) {
1450N/A ;
1450N/A }
1450N/A
1450N/A /*
1450N/A * perform the copy
1450N/A */
1450N/A (void) efb_wait_fifo(efb_priv, 3, "termemu_copy", __LINE__);
1450N/A regw(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
1450N/A regw(DP_DATATYPE, dp_datatype);
1450N/A regw(DP_CNTL, direction);
1450N/A (void) efb_wait_fifo(efb_priv, 3, "termemu_copy", __LINE__);
1450N/A regw(SRC_Y_X, (srcy << 16) | srcx);
1450N/A regw(DST_Y_X, (dsty << 16) | dstx);
1450N/A regw(DST_HEIGHT_WIDTH, (height << 16) | width);
1450N/A (void) efb_wait_idle(efb_priv, "termemu_copy", __LINE__);
1450N/A}
1450N/A
1450N/A/*
1450N/A * This function invalidates the user's GUI context.
1450N/A *
1450N/A * It MUST NOT be called in standalone (polled I/O mode). Polled I/O
1450N/A * operates within an incompatible set of constraints and liberties.
1450N/A *
1450N/A * If there is a user context currently active, this function tears
1450N/A * down the user mappings and saves the user's context. The strategy
1450N/A * is to make kernel operations uninterruptable from a user mapping,
1450N/A *
1450N/A * This routine exits HOLDING softc->softc_lock, WHICH THE *CALLER*
1450N/A * MUST RELEASE. This makes each of the following console functions atomic,
1450N/A * ie. Draw one character, scroll one line, render one cursor.
1450N/A *
1450N/A */
1450N/A
1450N/Astatic int
1450N/Aefb_invalidate_userctx(efb_private_t *efb_priv)
1450N/A{
1450N/A if (efb_priv->cur_ctx != NULL) {
1450N/A /*
1450N/A * Make sure it's safe to do the context switch
1450N/A */
1450N/A efb_ctx_wait(efb_priv);
1450N/A return (efb_ctx_make_current(efb_priv, NULL));
1450N/A }
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A
1450N/A/*
1450N/A * Validate the parameters for the data to be displayed on the
1450N/A * console.
1450N/A *
1450N/A * 1. Verify beginning (X,Y) coords are in the displayed area of fb.
1450N/A * 2. Verify that the character doesn't extend beyond displayed area.
1450N/A *
1450N/A * If characters exceed perimiter, clip if possible by adjusting
1450N/A * size of characters. This allows the terminal emulator to clear
1450N/A * the full screen or reverse video by writing characters all the way
1450N/A * to the screen edge, merely clipping rather than rejecting all
1450N/A * but the most egregious overlap.
1450N/A */
1450N/Astatic int
1450N/Aefb_chk_disp_params(efb_private_t *efb_priv, struct vis_consdisplay *disp)
1450N/A{
1450N/A if ((disp->row > efb_priv->h[efb_priv->consinfo.stream]) ||
1450N/A (disp->col > efb_priv->w[efb_priv->consinfo.stream]))
1450N/A return (EINVAL);
1450N/A
1450N/A if (((uint_t)disp->row + disp->height) >
1450N/A efb_priv->h[efb_priv->consinfo.stream]) {
1450N/A int d = (disp->row + disp->height) -
1450N/A efb_priv->h[efb_priv->consinfo.stream];
1450N/A if (d < disp->height)
1450N/A disp->height -= d;
1450N/A else
1450N/A return (EINVAL);
1450N/A }
1450N/A
1450N/A if (((uint_t)disp->col + disp->width) >
1450N/A efb_priv->w[efb_priv->consinfo.stream]) {
1450N/A int d = (disp->col + disp->width) -
1450N/A efb_priv->w[efb_priv->consinfo.stream];
1450N/A if (d < disp->width)
1450N/A disp->width -= d;
1450N/A else
1450N/A return (EINVAL);
1450N/A }
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A/*
1450N/A * Validate the parameters for the data to be displayed on the
1450N/A * console.
1450N/A *
1450N/A * 1. Verify beginning (X,Y) coords are in the displayed area of fb.
1450N/A * 2. Verify that the character doesn't extend beyond displayed area.
1450N/A */
1450N/Astatic int
1450N/Aefb_chk_cursor_params(efb_private_t *efb_priv, struct vis_conscursor *disp)
1450N/A{
1450N/A if ((disp->row > efb_priv->h[efb_priv->consinfo.stream]) ||
1450N/A (disp->col > efb_priv->w[efb_priv->consinfo.stream]))
1450N/A return (EINVAL);
1450N/A
1450N/A if (((uint_t)disp->row + disp->height) >
1450N/A efb_priv->h[efb_priv->consinfo.stream])
1450N/A return (EINVAL);
1450N/A
1450N/A if (((uint_t)disp->col + disp->width) >
1450N/A efb_priv->w[efb_priv->consinfo.stream])
1450N/A return (EINVAL);
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A/*
1450N/A * Validate the parameters for the source and destination rectangles.
1450N/A */
1450N/Astatic int
1450N/Aefb_chk_copy_params(efb_private_t *efb_priv, struct vis_conscopy *disp)
1450N/A{
1450N/A int width, height;
1450N/A int s = efb_priv->consinfo.stream;
1450N/A
1450N/A if ((0 > disp->e_col) || (disp->e_col > efb_priv->w[s]) ||
1450N/A (0 > disp->s_col) || (disp->s_col > efb_priv->w[s]) ||
1450N/A (0 > disp->t_col) || (disp->t_col > efb_priv->w[s]))
1450N/A return (EINVAL);
1450N/A
1450N/A width = disp->e_col - disp->s_col;
1450N/A height = disp->e_row - disp->s_row;
1450N/A
1450N/A if ((0 > width) || (width > efb_priv->w[s]) ||
1450N/A (0 > height) || (height > efb_priv->h[s]))
1450N/A return (EINVAL);
1450N/A
1450N/A if ((disp->t_row + height) > efb_priv->h[s])
1450N/A return (EINVAL);
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/A/*
1450N/A * Since being in polled I/O mode, the kernel already has
1450N/A * exclusive access to hardware, so we do not need to
1450N/A * invalidate user context.
1450N/A */
1450N/Astatic void
1450N/Aefb_polled_check_power(efb_private_t *efb_priv)
1450N/A{
1450N/A#if 0
1450N/A if (efb_priv->power_level[EFB_PM_BOARD] < EFB_PWR_ON) {
1450N/A efb_set_board_power(efb_priv, EFB_PWR_ON);
1450N/A }
1450N/A
1450N/A if (efb_priv->consinfo.stream == 0) {
1450N/A if (efb_priv->power_level[EFB_PM_MONITOR] < EFB_PWR_ON)
1450N/A efb_set_monitor_power1(efb_priv, EFB_PWR_ON);
1450N/A } else {
1450N/A if (efb_priv->power_level[EFB_PM_MONITOR2] < EFB_PWR_ON)
1450N/A efb_set_monitor_power2(efb_priv, EFB_PWR_ON);
1450N/A }
1450N/A#else
1450N/A _NOTE(ARGUNUSED(efb_priv))
1450N/A#endif
1450N/A}
1450N/A
1450N/Astatic void
1450N/Aefb_polledio_enter(void)
1450N/A{
1450N/A efb_in_polledio = 1;
1450N/A}
1450N/A
1450N/Astatic void
1450N/Aefb_polledio_exit(void)
1450N/A{
1450N/A efb_in_polledio = 0;
1450N/A}
1450N/A
1450N/A#endif /* VIS_CONS_REV */