patch-2.1.126 linux/drivers/video/igafb.c
Next file: linux/drivers/video/imsttfb.c
Previous file: linux/drivers/video/iga.h
Back to the patch index
Back to the overall index
- Lines: 784
- Date:
Fri Oct 16 23:30:21 1998
- Orig file:
v2.1.125/linux/drivers/video/igafb.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.125/linux/drivers/video/igafb.c linux/drivers/video/igafb.c
@@ -0,0 +1,783 @@
+/*
+ * linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
+ *
+ * Copyright (C) 1998 Vladimir Roganov and Gleb Raiko
+ *
+ * This driver is partly based on the Frame buffer device for ATI Mach64
+ * and partially on VESA-related code.
+ *
+ * Copyright (C) 1997-1998 Geert Uytterhoeven
+ * Copyright (C) 1998 Bernd Harries
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+/******************************************************************************
+
+ TODO:
+ Despite of IGA Card has advanced graphic acceleration,
+ initial version is almost dummy and does not support it.
+ Support for video modes and acceleration must be added
+ together with accelerated X-Windows driver implementation.
+
+ (Anyone to help with this?)
+
+ Most important thing at this moment is that we have working
+ JavaEngine1 console & X with new console interface.
+
+******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
+#include <asm/io.h>
+
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/pcic.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "iga.h"
+
+static char igafb_name[16] = "IGA 1682";
+static char fontname[40] __initdata = { 0 };
+
+struct pci_mmap_map {
+ unsigned long voff;
+ unsigned long poff;
+ unsigned long size;
+ unsigned long prot_flag;
+ unsigned long prot_mask;
+};
+
+struct fb_info_iga {
+ struct fb_info fb_info;
+ unsigned long frame_buffer_phys;
+ unsigned long frame_buffer;
+ unsigned long io_base_phys;
+ unsigned long io_base;
+ u32 total_vram;
+ struct pci_mmap_map *mmap_map;
+ struct { u_short blue, green, red, pad; } palette[256];
+ int video_cmap_len;
+ int currcon;
+ struct display disp;
+ struct display_switch dispsw;
+ union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+ } fbcon_cmap;
+#ifdef __sparc__
+ u8 open;
+ u8 mmaped;
+ int vtconsole;
+ int consolecnt;
+#endif
+};
+
+struct fb_var_screeninfo default_var = {
+ /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+ 640, 480, 640, 480, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+};
+
+#ifdef __sparc__
+struct fb_var_screeninfo default_var_1024x768 __initdata = {
+ /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+ 1024, 768, 1024, 768, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1152x900 __initdata = {
+ /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
+ 1152, 900, 1152, 900, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1280x1024 __initdata = {
+ /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+ 1280, 1024, 1280, 1024, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+/*
+ * Memory-mapped I/O functions for Sparc PCI
+ */
+static inline unsigned char pci_inb (struct fb_info_iga *info,
+ unsigned int reg)
+{
+ return *(volatile unsigned char*)(info->io_base + reg);
+}
+static inline void pci_outb (struct fb_info_iga *info, unsigned char c,
+ unsigned int reg)
+{
+ *(volatile unsigned char*)(info->io_base + reg) = c;
+}
+static inline unsigned int iga_inb(struct fb_info_iga *info,
+ unsigned int reg, unsigned int idx )
+{
+ pci_outb(info, idx, reg);
+ return pci_inb(info, reg + 1);
+}
+static inline void iga_outb(struct fb_info_iga *info, unsigned char val,
+ unsigned int reg, unsigned int idx )
+{
+ pci_outb(info, idx, reg);
+ pci_outb(info, val, reg+1);
+}
+
+#endif /* __sparc__ */
+
+/*
+ * Very important functionality for the JavaEngine1 computer:
+ * make screen border black (usign special IGA registers)
+ */
+static void iga_blank_border(struct fb_info_iga *info)
+{
+ int i;
+
+ for (i=0; i < 3; i++)
+ iga_outb(info, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
+}
+
+
+/*
+ * Frame buffer device API
+ */
+
+/*
+ * Open/Release the frame buffer device
+ */
+
+static int igafb_open(struct fb_info *info, int user)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int igafb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static int igafb_update_var(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+static int igafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct fb_info_iga *fb = (struct fb_info_iga*)info;
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, igafb_name);
+
+ fix->smem_start = (char *)fb->frame_buffer;
+ fix->smem_len = fb->total_vram;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->line_length = default_var.xres * (default_var.bits_per_pixel/8);
+ fix->visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+ return 0;
+}
+
+static int igafb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if(con == -1)
+ memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+ else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+static int igafb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+ return 0;
+}
+
+#ifdef __sparc__
+static int igafb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fb_info_iga *fb = (struct fb_info_iga *)info;
+ unsigned int size, page, map_size = 0;
+ unsigned long map_offset = 0;
+ int i;
+
+ if (!fb->mmap_map)
+ return -ENXIO;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages. */
+ vma->vm_flags |= (VM_SHM | VM_LOCKED);
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ) {
+ map_size = 0;
+ for (i = 0; fb->mmap_map[i].size; i++) {
+ unsigned long start = fb->mmap_map[i].voff;
+ unsigned long end = start + fb->mmap_map[i].size;
+ unsigned long offset = vma->vm_offset + page;
+
+ if (start > offset)
+ continue;
+ if (offset >= end)
+ continue;
+
+ map_size = fb->mmap_map[i].size - (offset - start);
+ map_offset = fb->mmap_map[i].poff + (offset - start);
+ break;
+ }
+ if (!map_size) {
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+
+ pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
+ pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
+
+ if (remap_page_range(vma->vm_start + page, map_offset,
+ map_size, vma->vm_page_prot))
+ return -EAGAIN;
+
+ page += map_size;
+ }
+
+ if (!map_size)
+ return -EINVAL;
+
+ vma->vm_file = file;
+ file->f_count++;
+ vma->vm_flags |= VM_IO;
+
+ if (!fb->mmaped) {
+ int lastconsole = 0;
+
+ if (info->display_fg)
+ lastconsole = info->display_fg->vc_num;
+ fb->mmaped = 1;
+ if (fb->consolecnt && fb_display[lastconsole].fb_info ==info) {
+ fb->vtconsole = lastconsole;
+ vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
+ }
+ }
+ return 0;
+}
+#endif /* __sparc__ */
+
+
+static int iga_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *fb_info)
+{
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (regno >= info->video_cmap_len)
+ return 1;
+
+ *red = info->palette[regno].red;
+ *green = info->palette[regno].green;
+ *blue = info->palette[regno].blue;
+ *transp = 0;
+ return 0;
+}
+
+static int iga_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info)
+{
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (regno >= info->video_cmap_len)
+ return 1;
+
+ info->palette[regno].red = red;
+ info->palette[regno].green = green;
+ info->palette[regno].blue = blue;
+
+ pci_outb(info, regno, DAC_W_INDEX);
+ pci_outb(info, red, DAC_DATA);
+ pci_outb(info, green, DAC_DATA);
+ pci_outb(info, blue, DAC_DATA);
+
+ if (regno << 16)
+ switch (default_var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ info->fbcon_cmap.cfb16[regno] =
+ (regno << 10) | (regno << 5) | regno;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ info->fbcon_cmap.cfb24[regno] =
+ (regno << 16) | (regno << 8) | regno;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ i = (regno << 8) | regno;
+ info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *fb_info)
+{
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (con != info->currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1,
+ iga_setcolreg, &info->fb_info);
+ else
+ fb_set_cmap(fb_default_cmap(info->video_cmap_len), 1,
+ iga_setcolreg, &info->fb_info);
+}
+
+static int igafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *fb_info)
+{
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (con == info->currcon) /* current console? */
+ return fb_get_cmap(cmap, kspc, iga_getcolreg, &info->fb_info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(info->video_cmap_len),
+ cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+static int igafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+ struct fb_info_iga *fb = (struct fb_info_iga*) info;
+
+ if (!fb_display[con].cmap.len) { /* no colormap allocated? */
+ err = fb_alloc_cmap(&fb_display[con].cmap,
+ fb->video_cmap_len,0);
+ if (err)
+ return err;
+ }
+ if (con == fb->currcon) /* current console? */
+ return fb_set_cmap(cmap, kspc, iga_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int igafb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ /* no panning */
+ return -EINVAL;
+}
+
+static int igafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+/*
+ * Framebuffer option structure
+ */
+static struct fb_ops igafb_ops = {
+ igafb_open,
+ igafb_release,
+ igafb_get_fix,
+ igafb_get_var,
+ igafb_set_var,
+ igafb_get_cmap,
+ igafb_set_cmap,
+ igafb_pan_display,
+ igafb_ioctl,
+#ifdef __sparc__
+ igafb_mmap
+#else
+ NULL
+#endif
+};
+
+static void igafb_set_disp(int con, struct fb_info_iga *info)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+ struct display_switch *sw;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &info->disp; /* used during initialization */
+
+ igafb_get_fix(&fix, con, &info->fb_info);
+
+ memset(display, 0, sizeof(struct display));
+ display->screen_base = (char*)info->frame_buffer;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 0;
+ display->inverse = 0;
+ igafb_get_var(&display->var, -1, &info->fb_info);
+
+ switch (default_var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ sw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ sw = &fbcon_cfb16;
+ display->dispsw_data = fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ sw = &fbcon_cfb24;
+ display->dispsw_data = fbcon_cmap.cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ sw = &fbcon_cfb32;
+ display->dispsw_data = fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ return;
+ }
+ memcpy(&info->dispsw, sw, sizeof(*sw));
+ display->dispsw = &info->dispsw;
+
+ display->scrollmode = SCROLL_YREDRAW;
+ info->dispsw.bmove = fbcon_redraw_bmove;
+}
+
+static int igafb_switch(int con, struct fb_info *fb_info)
+{
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ /* Do we have to save the colormap? */
+ if (fb_display[info->currcon].cmap.len)
+ fb_get_cmap(&fb_display[info->currcon].cmap, 1,
+ iga_getcolreg, fb_info);
+
+ info->currcon = con;
+ /* Install new colormap */
+ do_install_cmap(con, fb_info);
+ igafb_update_var(con, fb_info);
+ return 1;
+}
+
+
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void igafb_blank(int blank, struct fb_info *info)
+{
+ /* Not supported */
+}
+
+
+__initfunc(static int iga_init(struct fb_info_iga *info))
+{
+ char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL)
+ & MEM_SIZE_ALIAS;
+ switch (vramsz) {
+ case MEM_SIZE_1M:
+ info->total_vram = 0x100000;
+ break;
+ case MEM_SIZE_2M:
+ info->total_vram = 0x200000;
+ break;
+ case MEM_SIZE_4M:
+ case MEM_SIZE_RESERVED:
+ info->total_vram = 0x400000;
+ break;
+ }
+
+ if (default_var.bits_per_pixel > 8) {
+ info->video_cmap_len = 16;
+ } else {
+ int i, j;
+ for(i = 0; i < 16; i++) {
+ j = color_table[i];
+ info->palette[i].red = default_red[j];
+ info->palette[i].green = default_grn[j];
+ info->palette[i].blue = default_blu[j];
+ }
+ info->video_cmap_len = 256;
+ }
+
+ strcpy(info->fb_info.modename, igafb_name);
+ info->fb_info.node = -1;
+ info->fb_info.fbops = &igafb_ops;
+ info->fb_info.disp = &info->disp;
+ strcpy(info->fb_info.fontname, fontname);
+ info->fb_info.changevar = NULL;
+ info->fb_info.switch_con = &igafb_switch;
+ info->fb_info.updatevar = &igafb_update_var;
+ info->fb_info.blank = &igafb_blank;
+ info->fb_info.flags=FBINFO_FLAG_DEFAULT;
+
+ {
+ int j, k;
+ for (j = 0; j < 16; j++) {
+ k = color_table[j];
+ info->palette[j].red = default_red[k];
+ info->palette[j].green = default_grn[k];
+ info->palette[j].blue = default_blu[k];
+ }
+ }
+
+ igafb_set_disp(-1, info);
+
+ if (register_framebuffer(&info->fb_info) < 0)
+ return 0;
+
+ printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
+ GET_FB_IDX(info->fb_info.node), igafb_name,
+ info->frame_buffer_phys, info->total_vram >> 20);
+
+ iga_blank_border(info);
+ return 1;
+}
+
+
+__initfunc(void igafb_init(void))
+{
+ struct pci_dev *pdev;
+ struct fb_info_iga *info;
+ unsigned long addr;
+ extern int con_is_present(void);
+
+ /* Do not attach when we have a serial console. */
+ if (!con_is_present())
+ return;
+
+ pdev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ PCI_DEVICE_ID_INTERG_1682, 0);
+ if(pdev == NULL)
+ return;
+
+ info = kmalloc(sizeof(struct fb_info_iga), GFP_ATOMIC);
+ if (!info) {
+ printk("igafb_init: can't alloc fb_info_iga\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct fb_info_iga));
+
+ info->frame_buffer = pdev->base_address[0];
+ if (!info->frame_buffer)
+ return;
+
+ pcibios_read_config_dword(0, pdev->devfn,
+ PCI_BASE_ADDRESS_0,
+ (unsigned int*)&addr);
+ if (!addr)
+ return;
+ info->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
+
+#ifdef __sparc__
+
+ info->io_base_phys = info->frame_buffer_phys;
+
+ /* Obtain virtual address and correct physical by PCIC shift */
+ info->io_base = pcic_alloc_io(&info->io_base_phys);
+ if (!info->io_base) {
+ return;
+ }
+
+ /*
+ * Figure mmap addresses from PCI config space.
+ * We need two regions: for video memory and for I/O ports.
+ * Later one can add region for video coprocessor registers.
+ * However, mmap routine loops until size != 0, so we put
+ * one additional region with size == 0.
+ */
+
+ info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
+ if (!info->mmap_map) {
+ printk("igafb_init: can't alloc mmap_map\n");
+ kfree(info);
+ return;
+ }
+
+ memset(info->mmap_map, 0, 4 * sizeof(*info->mmap_map));
+
+ /*
+ * Set default vmode and cmode from PROM properties.
+ */
+ {
+ struct pcidev_cookie *cookie = pdev->sysdata;
+ int node = cookie->prom_node;
+ int width = prom_getintdefault(node, "width", 1024);
+ int height = prom_getintdefault(node, "height", 768);
+ int depth = prom_getintdefault(node, "depth", 8);
+ switch (width) {
+ case 1024:
+ if (height == 768)
+ default_var = default_var_1024x768;
+ break;
+ case 1152:
+ if (height == 900)
+ default_var = default_var_1152x900;
+ break;
+ case 1280:
+ if (height == 1024)
+ default_var = default_var_1280x1024;
+ break;
+ default:
+ break;
+ }
+
+ switch (depth) {
+ case 8:
+ default_var.bits_per_pixel = 8;
+ break;
+ case 16:
+ default_var.bits_per_pixel = 16;
+ break;
+ case 24:
+ default_var.bits_per_pixel = 24;
+ break;
+ case 32:
+ default_var.bits_per_pixel = 32;
+ break;
+ default:
+ break;
+ }
+ }
+
+#endif
+ if (!iga_init(info)) {
+ if (info->mmap_map)
+ kfree(info->mmap_map);
+ kfree(info);
+ }
+
+#ifdef __sparc__
+ /*
+ * Add /dev/fb mmap values.
+ */
+
+ /* First region is for video memory */
+ info->mmap_map[0].voff = 0x0;
+ info->mmap_map[0].poff = info->frame_buffer_phys & PAGE_MASK;
+ info->mmap_map[0].size = info->total_vram & PAGE_MASK;
+ info->mmap_map[0].prot_mask = SRMMU_CACHE;
+ info->mmap_map[0].prot_flag = SRMMU_WRITE;
+
+ /* Second region is for I/O ports */
+ info->mmap_map[1].voff = info->frame_buffer_phys & PAGE_MASK;
+ info->mmap_map[1].poff = info->io_base_phys & PAGE_MASK;
+ info->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
+ info->mmap_map[1].prot_mask = SRMMU_CACHE;
+ info->mmap_map[1].prot_flag = SRMMU_WRITE;
+#endif /* __sparc__ */
+}
+
+__initfunc(void igafb_setup(char *options, int *ints))
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return;
+
+ for (this_opt = strtok(options, ","); this_opt;
+ this_opt = strtok(NULL, ",")) {
+ if (!strncmp(this_opt, "font:", 5)) {
+ char *p;
+ int i;
+
+ p = this_opt + 5;
+ for (i = 0; i < sizeof(fontname) - 1; i++)
+ if (!*p || *p == ' ' || *p == ',')
+ break;
+ memcpy(fontname, this_opt + 5, i);
+ fontname[i] = 0;
+ }
+ }
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov