Goto sanos source index

//
// vga.c
//
// VGA graphics driver
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include <os/krnl.h>
#include <os/vga.h>

struct vga {
  struct vesa_mode_info *mode;  // Graphics mode
  unsigned char *fb;            // Frame buffer
  unsigned int fbsize;          // Frame buffer size
};

static int vga_ioctl(struct dev *dev, int cmd, void *args, size_t size) {
  struct vga *vga = (struct vga *) dev->privdata;

  switch (cmd) {
    case IOCTL_GETDEVSIZE:
      return vga->fbsize;

    case IOCTL_GETBLKSIZE:
      return 1;

    case IOCTL_VGA_GET_VIDEO_MODE:
      if (!args) return -EINVAL;
      if (size > sizeof(struct vesa_mode_info)) size = sizeof(struct vesa_mode_info);
      memcpy(args, vga->mode, size);
      return 0;

    case IOCTL_VGA_GET_FRAME_BUFFER:
      if (!args || size != sizeof(unsigned char *)) return -EINVAL;
      *((unsigned char **) args) = vga->fb;
      return 0;
  }

  return -ENOSYS;
}

static int vga_read(struct dev *dev, void *buffer, size_t count, blkno_t blkno, int flags) {
  struct vga *vga = (struct vga *) dev->privdata;

  if (blkno > vga->fbsize) return -EFAULT;
  if (blkno + count > vga->fbsize) count = vga->fbsize - blkno;
  if (count == 0) return 0;
  memcpy(buffer, vga->fb + blkno, count);

  return count;
}

static int vga_write(struct dev *dev, void *buffer, size_t count, blkno_t blkno, int flags) {
  struct vga *vga = (struct vga *) dev->privdata;

  if (blkno > vga->fbsize) return -EFAULT;
  if (blkno + count > vga->fbsize) count = vga->fbsize - blkno;
  if (count == 0) return 0;
  memcpy(vga->fb + blkno, buffer, count);

  return count;
}

static int color_mask(int size, int pos) {
  return size ? ((1 << size) - 1) << pos : 0;
}

static int vgainfo_proc(struct proc_file *pf, void *arg) {
  struct vga *vga = (struct vga *) arg;
  struct vesa_mode_info *info = vga->mode;

  pprintf(pf, "Resolution.......... : %dx%dx%d\n", info->x_resolution, info->y_resolution, info->bits_per_pixel);
  pprintf(pf, "Color resolution.... : R=%d G=%d B=%d A=%d\n", 
          1 << info->red_mask_size, 
          1 << info->green_mask_size, 
          1 << info->blue_mask_size, 
          1 << info->reserved_mask_size);
  pprintf(pf, "Character size...... : %dx%d\n", info->x_char_size, info->y_char_size);
  pprintf(pf, "VGA attributes...... : %x\n", info->attributes);
  pprintf(pf, "Bytes per scanline.. : %d\n", info->bytes_per_scanline);
  pprintf(pf, "Memory model........ : %d\n", info->memory_model);
  pprintf(pf, "Planes.............. : %d\n", info->number_of_planes);
  pprintf(pf, "Banks............... : %d\n", info->number_of_banks);
  pprintf(pf, "Bank size........... : %d\n", info->bank_size);
  pprintf(pf, "Image pages......... : %d\n", info->number_of_image_pages);
  pprintf(pf, "Color masks......... : R=%08x G=%08x B=%08x A=%08x\n", 
          color_mask(info->red_mask_size, info->red_mask_pos),
          color_mask(info->green_mask_size, info->green_mask_pos),
          color_mask(info->blue_mask_size, info->blue_mask_pos),
          color_mask(info->reserved_mask_size, info->reserved_mask_pos));
  pprintf(pf, "Reserved page....... : %d\n", info->reserved_page);
  pprintf(pf, "Direct color mode... : %d\n", info->direct_color_mode_info);
  pprintf(pf, "Frame buffer addr... : phys: %08x virt: %08X size: %d\n", info->phys_base_ptr, vga->fb, vga->fbsize);
  pprintf(pf, "Off-screen memory... : %08x (%d bytes)\n", info->off_screen_mem_offset, info->off_screen_mem_size);
  pprintf(pf, "Window A segment.... : %d\n", info->wina_segment);
  pprintf(pf, "Window B segment.... : %d\n", info->winb_segment);
  pprintf(pf, "Window func......... : %08x\n", info->win_func_ptr);

  return 0;
}

struct driver vga_driver = {
  "vga",
  DEV_TYPE_BLOCK,
  vga_ioctl,
  vga_read,
  vga_write
};

int __declspec(dllexport) vga(struct unit *unit) {
  struct vga *vga;
  struct vesa_mode_info *mode = (struct vesa_mode_info *) syspage->vgainfo;

  // Check if graphics mode is enabled
  if (!mode->phys_base_ptr) return 0;

  // Allocate memory for device
  vga = kmalloc(sizeof(struct vga));
  if (vga == NULL) return -ENOMEM;
  memset(vga, 0, sizeof(struct vga));
  vga->mode = mode;

  // Make frame buffer user accessible
  vga->fbsize = mode->y_resolution * mode->bytes_per_scanline;
  vga->fb = miomap(mode->phys_base_ptr, vga->fbsize, PAGE_READWRITE);
  if (!vga->fb) return -ENOMEM;

  dev_make("fb#", &vga_driver, unit, vga);

  // VGA information
  register_proc_inode("vgainfo", vgainfo_proc, vga);

  return 0;
}