Commit 4ff60c0f authored by James Simmons's avatar James Simmons

Supprt for switching hardware from/to vga text mode.

parent 23dda298
......@@ -6,7 +6,7 @@
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := fbmem.o fbcmap.o fbmon.o modedb.o softcursor.o cfbfillrect.o \
cfbcopyarea.o cfbimgblt.o cyber2000fb.o
cfbcopyarea.o cfbimgblt.o cyber2000fb.o vgastate.o
# Each configuration option enables a list of files.
......@@ -50,7 +50,8 @@ obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_S3TRIO) += S3triofb.o
obj-$(CONFIG_FB_TGA) += tgafb.o
obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_VIRGE) += virgefb.o
obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
......@@ -69,7 +70,8 @@ obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbi
obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_MATROX) += matrox/
obj-$(CONFIG_FB_RIVA) += riva/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_RIVA) += riva/ cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o
......
......@@ -1770,9 +1770,12 @@ static char * __init aty128find_ROM(void)
char *rom_base;
char *rom;
int stage;
int i;
int i, j;
char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */
char R128_sig[] = "R128"; /* Rage128 ROM identifier */
char *R128_sig[] = {
"R128", /* Rage128 ROM identifier */
"128b"
};
for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
stage = 1;
......@@ -1803,10 +1806,14 @@ static char * __init aty128find_ROM(void)
/* ATI signature found. Let's see if it's a Rage128 */
for (i = 0; (i < 512) && (stage != 4); i++) {
if (R128_sig[0] == *rom)
if (strncmp(R128_sig, rom,
strlen(R128_sig)) == 0)
stage = 4;
for (j = 0; j < sizeof(R128_sig)/sizeof(char *);j++) {
if (R128_sig[j][0] == *rom)
if (strncmp(R128_sig[j], rom,
strlen(R128_sig[j])) == 0) {
stage = 4;
break;
}
}
rom++;
}
if (stage != 4) {
......
......@@ -123,11 +123,11 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
shift = start_index;
}
while (n--) {
if (p->fix.visual == FB_VISUAL_PSEUDOCOLOR)
color = *src & bitmask;
if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
p->fix.visual == FB_VISUAL_DIRECTCOLOR )
color = palette[*src] & bitmask;
else
color = *src & bitmask;
val |= SHIFT_HIGH(color, shift);
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
......
This diff is collapsed.
......@@ -730,12 +730,12 @@ fb_open(struct inode *inode, struct file *file)
#endif /* CONFIG_KMOD */
if (!(info = registered_fb[fbidx]))
return -ENODEV;
if (info->fbops->owner)
__MOD_INC_USE_COUNT(info->fbops->owner);
if (!try_module_get(info->fbops->owner))
return -ENODEV;
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res && info->fbops->owner)
__MOD_DEC_USE_COUNT(info->fbops->owner);
if (res)
module_put(info->fbops->owner);
}
return res;
}
......@@ -750,8 +750,7 @@ fb_release(struct inode *inode, struct file *file)
info = registered_fb[fbidx];
if (info->fbops->fb_release)
info->fbops->fb_release(info,1);
if (info->fbops->owner)
__MOD_DEC_USE_COUNT(info->fbops->owner);
module_put(info->fbops->owner);
unlock_kernel();
return 0;
}
......
......@@ -42,8 +42,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/console.h>
#include <linux/selection.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pci.h>
......@@ -54,7 +52,7 @@
#if defined(__powerpc__)
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <video/macmodes.h>
#include "macmodes.h"
#ifdef CONFIG_NVRAM
#include <linux/nvram.h>
......@@ -80,10 +78,8 @@
#endif
#include <video/radeon.h>
#include <linux/radeonfb.h>
#define DEBUG 1
#if DEBUG
......@@ -681,7 +677,6 @@ static __inline__ int _max(int val1, int val2)
* globals
*/
static char fontname[40] __initdata;
static char *mode_option __initdata;
static char noaccel = 1;
static char mirror = 0;
......@@ -1295,7 +1290,6 @@ static int __devinit radeon_init_disp (struct radeonfb_info *rinfo)
var.activate = FB_ACTIVATE_NOW;
gen_set_var(&var, -1, info);
return 0;
}
......@@ -1495,7 +1489,7 @@ static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *in
}
static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con,
static int radeonfb_pan_display (struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
......@@ -1509,7 +1503,6 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con,
OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
* var->bits_per_pixel / 8) & ~7);
return 0;
}
......@@ -2188,11 +2181,8 @@ static void radeon_write_mode (struct radeonfb_info *rinfo,
static struct fb_ops radeonfb_ops = {
.owner = THIS_MODULE,
.fb_set_var = gen_set_var,
.fb_check_var = radeonfb_check_var,
.fb_set_par = radeonfb_set_par,
.fb_get_cmap = gen_get_cmap,
.fb_set_cmap = gen_set_cmap,
.fb_setcolreg = radeonfb_setcolreg,
.fb_pan_display = radeonfb_pan_display,
.fb_blank = radeonfb_blank,
......@@ -2228,11 +2218,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
info->fbops = &radeonfb_ops;
info->display_fg = NULL;
info->screen_base = (char *)rinfo->fb_base;
strncpy (info->fontname, fontname, sizeof (info->fontname));
info->fontname[sizeof (info->fontname) - 1] = 0;
info->changevar = NULL;
info->switch_con = gen_switch;
info->updatevar = gen_update_var;
/* Fill fix common fields */
strncpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
......@@ -3138,16 +3123,7 @@ int __init radeonfb_setup (char *options)
while ((this_opt = strsep (&options, ",")) != NULL) {
if (!*this_opt)
continue;
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);
} else if (!strncmp(this_opt, "noaccel", 7)) {
if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
} else if (!strncmp(this_opt, "mirror", 6)) {
mirror = 1;
......
......@@ -42,6 +42,7 @@
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#include "rivafb.h"
#include "nvreg.h"
......@@ -246,15 +247,12 @@ struct riva_cursor {
/* command line data, set in rivafb_setup() */
static u32 pseudo_palette[17];
static char nomove = 0;
#ifdef CONFIG_MTRR
static char nomtrr __initdata = 0;
#endif
#ifndef MODULE
static char *mode_option __initdata = NULL;
#else
static char *font = NULL;
#endif
static struct fb_fix_screeninfo rivafb_fix = {
......@@ -428,7 +426,7 @@ static void rivafb_load_cursor_image(u8 *data, u8 *mask, struct riva_par *par,
m = *((u32 *)mask)++;
for (j = 0; j < w/2; j++) {
tmp = 0;
#if defined (__BIG_ENDIAN)
#if defined (__BIG_ENDIAN__)
if (m & (1 << 31))
tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
b <<= 1;
......@@ -1162,6 +1160,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* framebuffer operations
*
* ------------------------------------------------------------------------- */
static int rivafb_open(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) {
memset(&par->state, 0, sizeof(struct fb_vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
/* save the DAC for Riva128 */
if (par->riva.Architecture == NV_ARCH_03)
par->state.flags |= VGA_SAVE_CMAP;
fb_save_vga(&par->state);
RivaGetConfig(&par->riva);
riva_save_state(par, &par->initial_state);
}
atomic_inc(&par->ref_count);
return 0;
}
static int rivafb_release(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt)
return -EINVAL;
if (cnt == 1) {
par->riva.LockUnlock(&par->riva, 0);
par->riva.LoadStateExt(&par->riva, &par->initial_state.ext);
fb_restore_vga(&par->state);
par->riva.LockUnlock(&par->riva, 1);
}
atomic_dec(&par->ref_count);
return 0;
}
static int rivafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
......@@ -1493,6 +1531,8 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
/* kernel interface */
static struct fb_ops riva_fb_ops = {
.owner = THIS_MODULE,
.fb_open = rivafb_open,
.fb_release = rivafb_release,
.fb_check_var = rivafb_check_var,
.fb_set_par = rivafb_set_par,
.fb_setcolreg = rivafb_setcolreg,
......@@ -1535,6 +1575,106 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
*
* ------------------------------------------------------------------------- */
static void __devinit rivafb_get_mem_len(struct riva_par *par,
struct fb_fix_screeninfo *fix)
{
RIVA_HW_INST *chip = &par->riva;
switch (chip->Architecture) {
case NV_ARCH_03:
if (chip->PFB[0x00000000/4] & 0x00000020) {
if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
&& ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {
/*
* SDRAM 128 ZX.
*/
switch (chip->PFB[0x00000000/4] & 0x03) {
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
case 1:
fix->smem_len = 1024 * 1024 * 2;
break;
default:
fix->smem_len = 1024 * 1024 * 8;
break;
}
}
else {
fix->smem_len = 1024 * 1024 * 8;
}
}
else {
/*
* SGRAM 128.
*/
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 8;
break;
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
default:
fix->smem_len = 1024 * 1024 * 2;
break;
}
}
break;
case NV_ARCH_04:
if (chip->PFB[0x00000000/4] & 0x00000100) {
fix->smem_len = (((chip->PFB[0x00000000/4] >> 12)
& 0x0F) * 1024 * 2 + 1024 * 2) * 1024;
}
else {
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 32;
break;
case 1:
fix->smem_len = 1024 * 1024 * 4;
break;
case 2:
fix->smem_len = 1024 * 1024 * 8;
break;
case 3:
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
break;
case NV_ARCH_10:
case NV_ARCH_20:
switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF) {
case 0x02:
fix->smem_len = 1024 * 1024 * 2;
break;
case 0x04:
fix->smem_len = 1024 * 1024 * 4;
break;
case 0x08:
fix->smem_len = 1024 * 1024 * 8;
break;
case 0x10:
fix->smem_len = 1024 * 1024 * 16;
break;
case 0x20:
fix->smem_len = 1024 * 1024 * 32;
break;
case 0x40:
fix->smem_len = 1024 * 1024 * 64;
break;
case 0x80:
fix->smem_len = 1024 * 1024 * 128;
break;
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
}
static int __devinit rivafb_init_one(struct pci_dev *pd,
const struct pci_device_id *ent)
{
......@@ -1586,14 +1726,22 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
}
default_par->riva.EnableIRQ = 0;
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base + 0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base + 0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base + 0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base + 0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base + 0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base + 0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base + 0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base + 0x00800000);
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base +
0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base +
0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base +
0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base +
0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base +
0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base +
0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base +
0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base +
0x00800000);
default_par->riva.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000);
default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000);
......@@ -1603,22 +1751,26 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
switch (default_par->riva.Architecture) {
case NV_ARCH_03:
default_par->riva.PRAMIN = (unsigned *)(info->screen_base + 0x00C00000);
default_par->riva.PRAMIN = (unsigned *)(info->screen_base +
0x00C00000);
default_par->dclk_max = 256000000;
rivafb_fix.accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04:
case NV_ARCH_10:
case NV_ARCH_20:
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base + 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base + 0x00710000);
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base
+ 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base
+ 0x00710000);
default_par->dclk_max = 250000000;
rivafb_fix.accel = FB_ACCEL_NV4;
break;
}
RivaGetConfig(&default_par->riva);
rivafb_get_mem_len(default_par, &rivafb_fix);
rivafb_fix.smem_len = default_par->riva.RamAmountKBytes * 1024;
default_par->dclk_max = default_par->riva.MaxVClockFreqKHz * 1000;
info->par = default_par;
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
......@@ -1648,14 +1800,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
}
#endif /* CONFIG_MTRR */
/* unlock io */
CRTCout(default_par, 0x11, 0xFF);/* vgaHWunlock() + riva unlock(0x7F) */
default_par->riva.LockUnlock(&default_par->riva, 0);
info->par = default_par;
riva_save_state(default_par, &default_par->initial_state);
if (riva_set_fbinfo(info) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n");
goto err_out_cursor;
......@@ -1680,7 +1824,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
return 0;
err_out_load_state:
riva_load_state(default_par, &default_par->initial_state);
err_out_cursor:
/* err_out_iounmap_fb: */
iounmap(info->screen_base);
......@@ -1704,8 +1847,6 @@ static void __devexit rivafb_remove_one(struct pci_dev *pd)
if (!info)
return;
riva_load_state(par, &par->initial_state);
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
......@@ -1742,13 +1883,11 @@ int __init rivafb_setup(char *options)
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
if (!strncmp(this_opt, "nomove", 6)) {
nomove = 1;
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
#endif
} else
#endif
mode_option = this_opt;
}
return 0;
......@@ -1773,9 +1912,7 @@ static struct pci_driver rivafb_driver = {
int __init rivafb_init(void)
{
int err;
#ifdef MODULE
if (font) strncpy(fontname, font, sizeof(fontname)-1);
#endif
err = pci_module_init(&rivafb_driver);
if (err)
return err;
......@@ -1796,8 +1933,6 @@ MODULE_PARM(font, "s");
MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)");
MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)");
MODULE_PARM(nomove, "i");
MODULE_PARM_DESC(nomove, "Enables YSCROLL_NOMOVE (0 or 1=enabled) (default=0)");
#ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
......
......@@ -34,7 +34,8 @@ struct riva_par {
struct riva_regs initial_state; /* initial startup video mode */
struct riva_regs current_state;
struct fb_vgastate state;
atomic_t ref_count;
riva_cfb8_cmap_t cmap[256]; /* VGA DAC palette cache */
u32 riva_palette[16];
u32 cursor_data[32 * 32/4];
......
......@@ -7,7 +7,8 @@
*
* 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. */
* archive for more details.
*/
#include <linux/module.h>
#include <linux/kernel.h>
......@@ -69,6 +70,8 @@ static struct vga16fb_par {
unsigned char ModeControl; /* CRT-Controller:17h */
unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state;
struct fb_vgastate state;
atomic_t ref_count;
int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv;
u8 crtc[VGA_CRT_C];
......@@ -295,6 +298,34 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
#define FAIL(X) return -EINVAL
static int vga16fb_open(struct fb_info *info, int user)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) {
memset(&par->state, 0, sizeof(struct fb_vgastate));
par->state.flags = 8;
fb_save_vga(&par->state);
}
atomic_inc(&par->ref_count);
return 0;
}
static int vga16fb_release(struct fb_info *info, int user)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt)
return -EINVAL;
if (cnt == 1)
fb_restore_vga(&par->state);
atomic_dec(&par->ref_count);
return 0;
}
static int vga16fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
......@@ -1346,6 +1377,8 @@ void vga16fb_imageblit(struct fb_info *info, struct fb_image *image)
static struct fb_ops vga16fb_ops = {
.owner = THIS_MODULE,
.fb_open = vga16fb_open,
.fb_release = vga16fb_release,
.fb_check_var = vga16fb_check_var,
.fb_set_par = vga16fb_set_par,
.fb_setcolreg = vga16fb_setcolreg,
......
This diff is collapsed.
......@@ -321,6 +321,37 @@ struct fb_cursor {
struct fb_image image; /* Cursor image */
};
/* VGA State Save and Restore */
#define VGA_SAVE_FONT0 1 /* save/restore plane 2 fonts */
#define VGA_SAVE_FONT1 2 /* save/restore plane 3 fonts */
#define VGA_SAVE_TEXT 4 /* save/restore plane 0/1 fonts */
#define VGA_SAVE_FONTS 7 /* save/restore all fonts */
#define VGA_SAVE_MODE 8 /* save/restore video mode */
#define VGA_SAVE_CMAP 16 /* save/restore color map/DAC */
struct fb_vgastate {
caddr_t vgabase; /* mmio base, if supported */
__u32 flags; /* what state/s to save (see VGA_SAVE_*) */
__u32 depth; /* current fb depth, not important */
__u32 num_attr; /* number of att registers, 0 for default */
__u32 num_crtc; /* number of crt registers, 0 for default */
__u32 num_gfx; /* number of gfx registers, 0 for default */
__u32 num_seq; /* number of seq registers, 0 for default */
caddr_t fbbase; /* -- DO NOT ALTER STARTING HERE -- */
__u8 *vga_font0;
__u8 *vga_font1;
__u8 *vga_text;
__u8 *vga_cmap;
__u8 *attr;
__u8 *crtc;
__u8 *gfx;
__u8 *seq;
__u8 misc;
};
extern int fb_save_vga(struct fb_vgastate *state);
extern int fb_restore_vga(struct fb_vgastate *state);
#ifdef __KERNEL__
#include <linux/fs.h>
......
......@@ -9,8 +9,8 @@
#include <linux/config.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/console_struct.h>
#include <linux/tty.h>
#include <linux/console_struct.h>
/*
* Presently, a lot of graphics programs do not restore the contents of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment