Commit 596e800f authored by James Simmons's avatar James Simmons

More porting to new api.

parent 6c369b2b
......@@ -45,7 +45,7 @@ obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_AMIGA) += amifb.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o
obj-$(CONFIG_FB_Q40) += q40fb.o
obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_ATARI) += atafb.o
obj-$(CONFIG_FB_ATY128) += aty128fb.o
obj-$(CONFIG_FB_RADEON) += radeonfb.o
......@@ -73,7 +73,7 @@ obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimg
obj-$(CONFIG_FB_VGA16) += vga16fb.o fbcon-vga-planes.o
obj-$(CONFIG_FB_VIRGE) += virgefb.o
obj-$(CONFIG_FB_G364) += g364fb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_CREATOR) += creatorfb.o sbusfb.o
obj-$(CONFIG_FB_CGSIX) += cgsixfb.o sbusfb.o
obj-$(CONFIG_FB_BWTWO) += bwtwofb.o sbusfb.o
......@@ -114,7 +114,7 @@ obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
obj-$(CONFIG_FB_HGA) += hgafb.o
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_E1355) += epson1355fb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
......
......@@ -70,40 +70,43 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image)
src = image->data;
if (p->fix.visual == FB_VISUAL_TRUECOLOR) {
fgx = fgcolor = ((u32 *)(p->pseudo_palette))[image->fg_color];
bgx = bgcolor = ((u32 *)(p->pseudo_palette))[image->bg_color];
} else {
fgx = fgcolor = image->fg_color;
bgx = bgcolor = image->bg_color;
}
if (image->depth == 1) {
if (p->fix.visual == FB_VISUAL_TRUECOLOR) {
fgx = fgcolor = ((u32 *)(p->pseudo_palette))[image->fg_color];
bgx = bgcolor = ((u32 *)(p->pseudo_palette))[image->bg_color];
} else {
fgx = fgcolor = image->fg_color;
bgx = bgcolor = image->bg_color;
}
for (i = 0; i < ppw-1; i++) {
fgx <<= p->var.bits_per_pixel;
bgx <<= p->var.bits_per_pixel;
fgx |= fgcolor;
bgx |= bgcolor;
}
eorx = fgx ^ bgx;
n = ((image->width + 7) >> 3);
pad = (n << 3) - image->width;
for (i = 0; i < ppw-1; i++) {
fgx <<= p->var.bits_per_pixel;
bgx <<= p->var.bits_per_pixel;
fgx |= fgcolor;
bgx |= bgcolor;
}
eorx = fgx ^ bgx;
n = ((image->width + 7) >> 3);
pad = (n << 3) - image->width;
for (i = 0; i < image->height; i++) {
dst = (unsigned long *) dst1;
for (i = 0; i < image->height; i++) {
dst = (unsigned long *) dst1;
for (j = image->width/ppw; j > 0; j--) {
mask = 0;
for (j = image->width/ppw; j > 0; j--) {
mask = 0;
for (k = ppw; k > 0; k--) {
if (test_bit(l, src))
mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
l--;
if (l < 0) { l = 7; src++; }
for (k = ppw; k > 0; k--) {
if (test_bit(l, src))
mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
l--;
if (l < 0) { l = 7; src++; }
}
fb_writel((mask & eorx)^bgx, dst);
dst++;
}
fb_writel((mask & eorx)^bgx, dst);
dst++;
}
l =- pad;
dst1 += p->fix.line_length;
}
l =- pad;
dst1 += p->fix.line_length;
}
}
}
......@@ -7,6 +7,7 @@
*
* Written for 2.0.x by Steffen A. Mork
* Ported to 2.1.x by Geert Uytterhoeven
* Ported to new api by James Simmons
*
* 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
......@@ -18,12 +19,9 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/zorro.h>
#include <asm/io.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb32.h>
/*
* Some technical notes:
......@@ -117,7 +115,6 @@
*
*/
/*
* definitions
*/
......@@ -130,29 +127,22 @@
#define FRAMEMASTER_COMPL 4
#define FRAMEMASTER_ROM 8
struct FrameMaster_fb_par
{
int xres;
int yres;
int bpp;
int pixclock;
};
static unsigned long fm2fb_mem_phys;
static void *fm2fb_mem;
static unsigned long fm2fb_reg_phys;
static volatile unsigned char *fm2fb_reg;
static struct display disp;
static struct fb_info fb_info;
static struct { u_char red, green, blue, pad; } palette[16];
#ifdef FBCON_HAS_CFB32
static u32 fbcon_cfb32_cmap[16];
#endif
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
static struct fb_fix_screeninfo fb_fix;
static struct fb_var_screeninfo fb_var;
static struct fb_info fb_info;
static u32 pseudo_palette[17];
static struct display display;
static struct fb_fix_screeninfo fb_fix __initdata = {
smem_len: FRAMEMASTER_REG,
type: FB_TYPE_PACKED_PIXELS,
visual: FB_VISUAL_TRUECOLOR,
line_length: (768 << 2),
mmio_len: (8),
accel: FB_ACCEL_NONE,
};
static int fm2fb_mode __initdata = -1;
......@@ -174,125 +164,58 @@ static struct fb_var_screeninfo fb_var_modes[] __initdata = {
33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0
}
};
/*
* Interface used by the world
*/
int fm2fb_init(void);
static int fm2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
static int fm2fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int fm2fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int fm2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
u_int transp, struct fb_info *info);
static int fm2fb_blank(int blank, struct fb_info *info);
/*
* Interface to the low level console driver
*/
int fm2fb_init(void);
static int fm2fbcon_switch(int con, struct fb_info *info);
static int fm2fbcon_updatevar(int con, struct fb_info *info);
/*
* Internal routines
*/
static int fm2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
u_int *transp, struct fb_info *info);
static struct fb_ops fm2fb_ops = {
owner: THIS_MODULE,
fb_get_fix: fm2fb_get_fix,
fb_get_var: fm2fb_get_var,
fb_set_var: fm2fb_set_var,
fb_get_cmap: fm2fb_get_cmap,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_set_var: gen_set_var,
fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap,
fb_setcolreg: fm2fb_setcolreg,
fb_blank: fm2fb_blank,
fb_blank: fm2fb_blank,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
};
/*
* Get the Fixed Part of the Display
* Blank the display.
*/
static int fm2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info)
static int fm2fb_blank(int blank, struct fb_info *info)
{
memcpy(fix, &fb_fix, sizeof(fb_fix));
return 0;
}
/*
* Get the User Defined Part of the Display
*/
unsigned char t = FRAMEMASTER_ROM;
static int fm2fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
memcpy(var, &fb_var, sizeof(fb_var));
return 0;
if (!blank)
t |= FRAMEMASTER_ENABLE | FRAMEMASTER_NOLACE;
fm2fb_reg[0] = t;
}
/*
* Set the User Defined Part of the Display
* 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.
*/
static int fm2fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
struct display *display;
int oldbpp = -1, err;
if (con >= 0)
display = &fb_display[con];
else
display = &disp; /* used during initialization */
if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
var->xres_virtual > fb_var.xres_virtual ||
var->yres_virtual > fb_var.yres_virtual ||
var->bits_per_pixel > fb_var.bits_per_pixel ||
var->nonstd ||
(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
return -EINVAL;
memcpy(var, &fb_var, sizeof(fb_var));
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
oldbpp = display->var.bits_per_pixel;
display->var = *var;
}
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
do_install_cmap(con, info);
}
return 0;
}
/*
* Get the Colormap
*/
if (regno > 15)
return 1;
red >>= 8;
green >>= 8;
blue >>= 8;
static int fm2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
if (con == info->currcon) /* current console? */
return fb_get_cmap(cmap, kspc, fm2fb_getcolreg, 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(256), cmap, kspc ? 0 : 2);
return 0;
((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue;
return 0;
}
/*
......@@ -301,194 +224,89 @@ static int fm2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
int __init fm2fb_init(void)
{
int is_fm;
struct zorro_dev *z = NULL;
unsigned long *ptr;
int x, y;
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
if (z->id == ZORRO_PROD_BSC_FRAMEMASTER_II)
is_fm = 1;
else if (z->id == ZORRO_PROD_HELFRICH_RAINBOW_II)
is_fm = 0;
else
continue;
if (!request_mem_region(z->resource.start, FRAMEMASTER_SIZE, "fm2fb"))
continue;
/* assigning memory to kernel space */
fm2fb_mem_phys = z->resource.start;
fm2fb_mem = ioremap(fm2fb_mem_phys, FRAMEMASTER_SIZE);
fm2fb_reg_phys = fm2fb_mem_phys+FRAMEMASTER_REG;
fm2fb_reg = (unsigned char *)(fm2fb_mem+FRAMEMASTER_REG);
/* make EBU color bars on display */
ptr = (unsigned long *)fm2fb_mem;
for (y = 0; y < 576; y++) {
for (x = 0; x < 96; x++) *ptr++ = 0xffffff; /* white */
for (x = 0; x < 96; x++) *ptr++ = 0xffff00; /* yellow */
for (x = 0; x < 96; x++) *ptr++ = 0x00ffff; /* cyan */
for (x = 0; x < 96; x++) *ptr++ = 0x00ff00; /* green */
for (x = 0; x < 96; x++) *ptr++ = 0xff00ff; /* magenta */
for (x = 0; x < 96; x++) *ptr++ = 0xff0000; /* red */
for (x = 0; x < 96; x++) *ptr++ = 0x0000ff; /* blue */
for (x = 0; x < 96; x++) *ptr++ = 0x000000; /* black */
struct zorro_dev *z = NULL;
unsigned long *ptr;
int is_fm;
int x, y;
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
if (z->id == ZORRO_PROD_BSC_FRAMEMASTER_II)
is_fm = 1;
else if (z->id == ZORRO_PROD_HELFRICH_RAINBOW_II)
is_fm = 0;
else
continue;
if (!request_mem_region(z->resource.start, FRAMEMASTER_SIZE, "fm2fb"))
continue;
/* assigning memory to kernel space */
fb_fix.smem_start = z->resource.start;
fb_info.screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE);
fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG;
fm2fb_reg = (unsigned char *)(fb_info.screen_base+FRAMEMASTER_REG);
strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II");
/* make EBU color bars on display */
ptr = (unsigned long *)fb_fix.smem_start;
for (y = 0; y < 576; y++) {
for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */
for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */
for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */
for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */
for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */
for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */
for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */
for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */
}
fm2fb_blank(0, NULL);
if (fm2fb_mode == -1)
fm2fb_mode = FM2FB_MODE_PAL;
strcpy(fb_info.modename, fb_fix.id);
fb_info.node = NODEV;
fb_info.fbops = &fm2fb_ops;
fb_info.var = fb_var_modes[fm2fb_mode];
fb_info.screen_base = (char *)fb_fix.smem_start;
fb_info.pseudo_palette = pseudo_palette;
fb_info.fix = fb_fix;
fb_info.flags = FBINFO_FLAG_DEFAULT;
/* The below feilds will go away !!!! */
fb_info.currcon = -1;
strcpy(fb_info.modename, fb_info.fix.id);
fb_info.disp = &display;
fb_info.switch_con = gen_switch;
fb_info.updatevar = gen_update_var;
fb_alloc_cmap(&fb_info.cmap, 16, 0);
gen_set_disp(-1, &fb_info);
if (register_framebuffer(&fb_info) < 0)
return -EINVAL;
printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node), fb_fix.id);
return 0;
}
fm2fb_blank(0, NULL);
if (fm2fb_mode == -1)
fm2fb_mode = FM2FB_MODE_PAL;
fb_var = fb_var_modes[fm2fb_mode];
strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II");
fb_fix.smem_start = fm2fb_mem_phys;
fb_fix.smem_len = FRAMEMASTER_REG;
fb_fix.type = FB_TYPE_PACKED_PIXELS;
fb_fix.type_aux = 0;
fb_fix.visual = FB_VISUAL_TRUECOLOR;
fb_fix.line_length = 768<<2;
fb_fix.mmio_start = fm2fb_reg_phys;
fb_fix.mmio_len = 8;
fb_fix.accel = FB_ACCEL_NONE;
disp.var = fb_var;
disp.cmap.start = 0;
disp.cmap.len = 0;
disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
disp.visual = fb_fix.visual;
disp.type = fb_fix.type;
disp.type_aux = fb_fix.type_aux;
disp.ypanstep = 0;
disp.ywrapstep = 0;
disp.line_length = fb_fix.line_length;
disp.can_soft_blank = 1;
disp.inverse = 0;
#ifdef FBCON_HAS_CFB32
disp.dispsw = &fbcon_cfb32;
disp.dispsw_data = &fbcon_cfb32_cmap;
#else
disp.dispsw = &fbcon_dummy;
#endif
disp.scrollmode = SCROLL_YREDRAW;
strcpy(fb_info.modename, fb_fix.id);
fb_info.node = NODEV;
fb_info.fbops = &fm2fb_ops;
fb_info.screen_base = (char *)fm2fb_mem;
fb_info.currcon = -1;
fb_info.disp = &disp;
fb_info.fontname[0] = '\0';
fb_info.changevar = NULL;
fb_info.switch_con = &fm2fbcon_switch;
fb_info.updatevar = &fm2fbcon_updatevar;
fb_info.flags = FBINFO_FLAG_DEFAULT;
fm2fb_set_var(&fb_var, -1, &fb_info);
if (register_framebuffer(&fb_info) < 0)
return -EINVAL;
printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
fb_fix.id);
return 0;
}
return -ENXIO;
return -ENXIO;
}
int __init fm2fb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 0;
char *this_opt;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!strncmp(this_opt, "pal", 3))
fm2fb_mode = FM2FB_MODE_PAL;
else if (!strncmp(this_opt, "ntsc", 4))
fm2fb_mode = FM2FB_MODE_NTSC;
}
return 0;
}
static int fm2fbcon_switch(int con, struct fb_info *info)
{
/* Do we have to save the colormap? */
if (fb_display[info->currcon].cmap.len)
fb_get_cmap(&fb_display[info->currcon].cmap, 1, fm2fb_getcolreg, info);
info->currcon = con;
/* Install new colormap */
do_install_cmap(con, info);
return 0;
}
if (!options || !*options)
return 0;
/*
* Update the `var' structure (called by fbcon.c)
*/
static int fm2fbcon_updatevar(int con, struct fb_info *info)
{
/* Nothing */
return 0;
}
/*
* Blank the display.
*/
static int fm2fb_blank(int blank, struct fb_info *info)
{
unsigned char t = FRAMEMASTER_ROM;
if (!blank)
t |= FRAMEMASTER_ENABLE | FRAMEMASTER_NOLACE;
fm2fb_reg[0] = t;
return 0;
}
/*
* Read a single color register and split it into
* colors/transparent. Return != 0 for invalid regno.
*/
static int fm2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
u_int *transp, struct fb_info *info)
{
if (regno > 15)
return 1;
*red = (palette[regno].red<<8) | palette[regno].red;
*green = (palette[regno].green<<8) | palette[regno].green;
*blue = (palette[regno].blue<<8) | palette[regno].blue;
*transp = 0;
return 0;
}
/*
* 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.
*/
static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
if (regno > 15)
return 1;
red >>= 8;
green >>= 8;
blue >>= 8;
palette[regno].red = red;
palette[regno].green = green;
palette[regno].blue = blue;
#ifdef FBCON_HAS_CFB32
fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
#endif
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!strncmp(this_opt, "pal", 3))
fm2fb_mode = FM2FB_MODE_PAL;
else if (!strncmp(this_opt, "ntsc", 4))
fm2fb_mode = FM2FB_MODE_NTSC;
}
return 0;
}
MODULE_LICENSE("GPL");
......@@ -386,44 +386,6 @@ static int __init hga_card_detect(void)
*
* ------------------------------------------------------------------------- */
/**
* hga_get_fix - get the fixed part of the display
* @fix:struct fb_fix_screeninfo to fill in
* @con:unused
* @info:pointer to fb_info object containing info for current hga board
*
* This wrapper function copies @info->fix to @fix.
* A zero is returned on success and %-EINVAL for failure.
*/
int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
{
CHKINFO(-EINVAL);
DPRINTK("hga_get_fix: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
*fix = info->fix;
return 0;
}
/**
* hga_get_var - get the user defined part of the display
* @var:struct fb_var_screeninfo to fill in
* @con:unused
* @info:pointer to fb_info object containing info for current hga board
*
* This wrapper function copies @info->var to @var.
* A zero is returned on success and %-EINVAL for failure.
*/
int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
CHKINFO(-EINVAL);
DPRINTK("hga_get_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
*var = info->var;
return 0;
}
/**
* hga_set_var - set the user defined part of the display
* @var:new video mode
......@@ -596,8 +558,8 @@ static int hgafb_blank(int blank_mode, struct fb_info *info)
static struct fb_ops hgafb_ops = {
owner: THIS_MODULE,
fb_get_fix: hga_get_fix,
fb_get_var: hga_get_var,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_set_var: hga_set_var,
fb_get_cmap: hga_get_cmap,
fb_set_cmap: gen_set_cmap,
......
......@@ -21,6 +21,7 @@
#include <linux/delay.h>
#include <linux/nubus.h>
#include <linux/init.h>
#include <linux/fb.h>
#include <asm/machvec.h>
#include <asm/uaccess.h>
......@@ -28,347 +29,165 @@
#include <asm/io.h>
#include <asm/hd64461.h>
#include <linux/fb.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
struct hitfb_par
{
int x, y;
int bpp;
static struct fb_var_screeninfo hitfb_var __initdata = {
activate: FB_ACTIVATE_NOW,
height: -1,
width: -1,
vmode: FB_VMODE_NONINTERLACED,
};
struct hitfb_info {
struct fb_info_gen gen;
struct display disp;
struct hitfb_par current_par;
struct fb_var_screeninfo default_var;
int current_par_valid;
unsigned long hit_videobase, hit_videosize;
union {
#ifdef FBCON_HAS_CFB16
u16 cfb16[16];
#endif
} fbcon_cmap;
} fb_info = {
{},
{},
{},
{},
0, 0, 0,
{},
static struct fb_fix_screeninfo hitfb_fix __initdata = {
id: "Hitachi HD64461",
type: FB_TYPE_PACKED_PIXELS,
visual: FB_VISUAL_TRUECOLOR,
accel_flags: FB_ACCEL_NONE,
};
static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info);
static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
struct fb_info_gen *info);
static void hitfb_detect(void)
{
struct hitfb_par par;
unsigned short lcdclor, ldr3, ldvntr;
fb_info.hit_videobase = CONFIG_HD64461_IOBASE + 0x02000000;
fb_info.hit_videosize = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024;
lcdclor = inw(HD64461_LCDCLOR);
ldvntr = inw(HD64461_LDVNTR);
ldr3 = inw(HD64461_LDR3);
switch(ldr3&15) {
default:
case 4:
par.bpp = 8;
par.x = lcdclor;
break;
case 8:
par.bpp = 16;
par.x = lcdclor/2;
break;
}
par.y = ldvntr+1;
hitfb_set_par(&par, NULL);
hitfb_encode_var(&fb_info.default_var, &par, NULL);
}
static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
struct fb_info_gen *info)
{
const struct hitfb_par *par = fb_par;
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, "Hitachi HD64461");
fix->smem_start = fb_info.hit_videobase;
fix->smem_len = fb_info.hit_videosize;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
fix->visual = (par->bpp == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
fix->xpanstep = 0;
fix->ypanstep = 0;
fix->ywrapstep = 0;
switch(par->bpp) {
default:
case 8:
fix->line_length = par->x;
break;
case 16:
fix->line_length = par->x*2;
break;
}
return 0;
}
static int hitfb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
struct fb_info_gen *info)
{
struct hitfb_par *par = fb_par;
par->x = var->xres;
par->y = var->yres;
par->bpp = var->bits_per_pixel;
return 0;
}
static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
struct fb_info_gen *info)
{
const struct hitfb_par *par = fb_par;
memset(var, 0, sizeof(*var));
var->xres = par->x;
var->yres = par->y;
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
var->xoffset = 0;
var->yoffset = 0;
var->bits_per_pixel = par->bpp;
var->grayscale = 0;
var->transp.offset = 0;
var->transp.length = 0;
var->transp.msb_right = 0;
var->nonstd = 0;
var->activate = 0;
var->height = -1;
var->width = -1;
var->vmode = FB_VMODE_NONINTERLACED;
var->pixclock = 0;
var->sync = 0;
var->left_margin = 0;
var->right_margin = 0;
var->upper_margin = 0;
var->lower_margin = 0;
var->hsync_len = 0;
var->vsync_len = 0;
switch (var->bits_per_pixel) {
case 8:
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 16: /* RGB 565 */
var->red.offset = 11;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 6;
var->blue.offset = 0;
var->blue.length = 5;
var->transp.offset = 0;
var->transp.length = 0;
break;
}
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
return 0;
}
static void hitfb_get_par(void *par, struct fb_info_gen *info)
{
*(struct hitfb_par *)par = fb_info.current_par;
}
static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info)
{
const struct hitfb_par *par = fb_par;
fb_info.current_par = *par;
fb_info.current_par_valid = 1;
static u16 pseudo_palette[17];
static struct display display;
struct fb_info fb_info;
static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
switch (var->bits_per_pixel) {
case 8:
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 16: /* RGB 565 */
var->red.offset = 11;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 6;
var->blue.offset = 0;
var->blue.length = 5;
var->transp.offset = 0;
var->transp.length = 0;
break;
}
return 0;
}
static int hitfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *info)
static int hitfb_set_par(struct fb_info *info)
{
if (regno > 255)
return 1;
info->fix.visual = (info->var.bits_per_pixel == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
outw(regno<<8, HD64461_CPTRAR);
*red = inw(HD64461_CPTRDR)<<10;
*green = inw(HD64461_CPTRDR)<<10;
*blue = inw(HD64461_CPTRDR)<<10;
*transp = 0;
return 0;
switch(info->var.bits_per_pixel) {
default:
case 8:
info->fix.line_length = info->var.xres;
break;
case 16:
info->fix.line_length = info->var.xres*2;
break;
}
return 0;
}
static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
if (regno > 255)
return 1;
if (regno > 255)
return 1;
outw(regno<<8, HD64461_CPTWAR);
outw(red>>10, HD64461_CPTWDR);
outw(green>>10, HD64461_CPTWDR);
outw(blue>>10, HD64461_CPTWDR);
outw(regno << 8, HD64461_CPTWAR);
outw(red >> 10, HD64461_CPTWDR);
outw(green >> 10, HD64461_CPTWDR);
outw(blue >> 10, HD64461_CPTWDR);
if(regno<16) {
switch(fb_info.current_par.bpp) {
if (regno < 16) {
switch(info->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB16
case 16:
fb_info.fbcon_cmap.cfb16[regno] =
((red & 0xf800) ) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
break;
case 16:
((u16 *)(info->pseudo_palette))[regno] =
((red & 0xf800) ) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
break;
#endif
}
}
}
return 0;
}
static int hitfb_pan_display(const struct fb_var_screeninfo *var,
struct fb_info_gen *info)
{
if (!fb_info.current_par_valid)
return -EINVAL;
return 0;
}
static int hitfb_blank(int blank_mode, struct fb_info_gen *info)
{
if (!fb_info.current_par_valid)
return 1;
return 0;
return 0;
}
static void hitfb_set_disp(const void *fb_par, struct display *disp,
struct fb_info_gen *info)
{
const struct hitfb_par *par = fb_par;
disp->scrollmode = SCROLL_YREDRAW;
switch(((struct hitfb_par *)par)->bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
disp->dispsw = &fbcon_cfb8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
disp->dispsw = &fbcon_cfb16;
disp->dispsw_data = fb_info.fbcon_cmap.cfb16;
break;
#endif
default:
disp->dispsw = &fbcon_dummy;
}
}
struct fbgen_hwswitch hitfb_switch = {
hitfb_detect,
hitfb_encode_fix,
hitfb_decode_var,
hitfb_encode_var,
hitfb_get_par,
hitfb_set_par,
hitfb_getcolreg,
hitfb_pan_display,
hitfb_blank,
hitfb_set_disp
};
static struct fb_ops hitfb_ops = {
owner: THIS_MODULE,
fb_get_fix: fbgen_get_fix,
fb_get_var: fbgen_get_var,
fb_set_var: fbgen_set_var,
fb_get_cmap: fbgen_get_cmap,
fb_set_cmap: fbgen_set_cmap,
fb_setcolreg: hitfb_setcolreg,
fb_pan_display: fbgen_pan_display,
fb_blank: fbgen_blank,
owner: THIS_MODULE,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_set_var: gen_set_var,
fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap,
fb_check_var: hitfb_check_var,
fb_set_par: hitfb_set_par,
fb_setcolreg: hitfb_setcolreg,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
};
int __init hitfb_init(void)
{
strcpy(fb_info.gen.info.modename, "Hitachi HD64461");
fb_info.gen.info.node = NODEV;
fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
fb_info.gen.info.fbops = &hitfb_ops;
fb_info.gen.info.disp = &fb_info.disp;
fb_info.gen.info.currcon = 1;
fb_info.gen.info.changevar = NULL;
fb_info.gen.info.switch_con = &fbgen_switch;
fb_info.gen.info.updatevar = &fbgen_update_var;
fb_info.gen.parsize = sizeof(struct hitfb_par);
fb_info.gen.fbhw = &hitfb_switch;
fb_info.gen.fbhw->detect();
fb_info.screen_base = (void *)fb_info.hit_videobase;
fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
fb_info.disp.var.activate = FB_ACTIVATE_NOW;
fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
fbgen_set_disp(-1, &fb_info.gen);
do_install_cmap(0, &fb_info.gen);
if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL;
unsigned short lcdclor, ldr3, ldvntr;
hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
hitfb_fix.smem_len = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024;
lcdclor = inw(HD64461_LCDCLOR);
ldvntr = inw(HD64461_LDVNTR);
ldr3 = inw(HD64461_LDR3);
switch (ldr3&15) {
default:
case 4:
hitfb_var.bits_per_pixel = 8;
hitfb_var.xres = lcdclor;
break;
case 8:
hitfb_var.bits_per_pixel = 16;
hitfb_var.xres = lcdclor/2;
break;
}
hitfb_var.yres = ldvntr+1;
fb_info.node = NODEV;
fb_info.fbops = &hitfb_ops;
fb_info.var = hitfb_var;
fb_info.fix = hitfb_fix;
fb_info.pseudo_palette = pseudo_palette;
fb_info.flags = FBINFO_FLAG_DEFAULT;
strcpy(fb_info.modename, fb_info.fix.id);
fb_info.currcon = -1;
fb_info.disp = &display;
fb_info.changevar = NULL;
fb_info.switch_con = gen_switch;
fb_info.updatevar = gen_update_var;
fb_info.screen_base = (void *) hitfb_fix.smem_start;
size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16;
fb_alloc_cmap(&fb_info.cmap, size, 0);
gen_set_var(&fb_info.var, -1, &fb_info);
printk(KERN_INFO "fb%d: %s frame buffer device\n",
GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
if (register_framebuffer(&fb_info) < 0)
return -EINVAL;
return 0;
printk(KERN_INFO "fb%d: %s frame buffer device\n",
GET_FB_IDX(fb_info.node), fb_info.fix.id);
return 0;
}
......@@ -392,7 +211,6 @@ void cleanup_module(void)
}
#endif
/*
* Local variables:
* c-basic-offset: 4
......
/*
* linux/drivers/video/q40fb.c -- Q40 frame buffer device
*
* Copyright (C) 2001
*
* Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de>
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
......@@ -9,181 +21,68 @@
#include <asm/uaccess.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/system.h>
/*#include <asm/irq.h>*/
#include <asm/q40_master.h>
#include <linux/fb.h>
#include <linux/module.h>
#include <asm/pgtable.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb16.h>
#define FBIOSETSCROLLMODE 0x4611
#define Q40_PHYS_SCREEN_ADDR 0xFE800000
static u16 fbcon_cmap_cfb16[16];
static u32 pseudo_palette[17];
static struct fb_info fb_info;
static struct display display;
static struct fb_fix_screeninfo q40fb_fix __initdata = {
id: "Q40",
smem_len: 1024*1024,
type: FB_TYPE_PACKED_PIXELS,
visual: FB_VISUAL_TRUECOLOR,
line_length: 1024*2,
accel_flags: FB_ACCEL_NONE,
};
static struct fb_var_screeninfo q40fb_var __initdata = {
xres: 1024,
yres: 512,
xres_virtual: 1024,
yres_virtual: 512,
bits_per_pixel: 16,
red: {6, 5, 0},
green: {11, 5, 0},
blue: {0, 6, 0},
activate: FB_ACTIVATE_NOW,
height: 230,
width: 300,
vmode: FB_VMODE_NONINTERLACED,
};
/* frame buffer operations */
int q40fb_init(void);
static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int q40fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
struct fb_info *info);
static int q40fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
struct fb_info *info);
static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
const struct fb_info *info);
unsigned blue, unsigned transp,
struct fb_info *info);
static int q40con_switch(int con, struct fb_info *info);
static int q40con_updatevar(int con, struct fb_info *info);
static void q40fb_set_disp(int con, struct fb_info *info);
static struct display disp[MAX_NR_CONSOLES];
static struct fb_info fb_info;
static struct fb_ops q40fb_ops = {
owner: THIS_MODULE,
fb_get_fix: q40fb_get_fix,
fb_get_var: q40fb_get_var,
fb_set_var: q40fb_set_var,
fb_get_cmap: q40fb_get_cmap,
fb_set_cmap: q40fb_set_cmap,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_set_var: gen_set_var,
fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap,
fb_setcolreg: q40fb_setcolreg,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
};
static char q40fb_name[]="Q40";
static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info)
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id,"Q40");
fix->smem_start = info->screen_base;
fix->smem_len=1024*1024;
fix->type=FB_TYPE_PACKED_PIXELS;
fix->type_aux=0;
fix->visual=FB_VISUAL_TRUECOLOR; /* good approximation so far ..*/;
fix->xpanstep=0;
fix->ypanstep=0;
fix->ywrapstep=0;
fix->line_length=1024*2;
/* no mmio,accel ...*/
return 0;
}
static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
memset(var, 0, sizeof(struct fb_var_screeninfo));
var->xres=1024;
var->yres=512;
var->xres_virtual=1024;
var->yres_virtual=512;
var->xoffset=0;
var->yoffset=0;
var->bits_per_pixel=16;
var->grayscale=0;
var->nonstd=0;
var->activate=FB_ACTIVATE_NOW;
var->height=230; /* approx for my 17" monitor, more important */
var->width=300; /* than the absolute values is the unusual aspect ratio*/
var->red.offset=6; /*6*/
var->red.length=5;
var->green.offset=11; /*11*/
var->green.length=5;
var->blue.offset=0;
var->blue.length=6;
var->transp.length=0;
var->pixclock=0;
var->left_margin=0;
var->right_margin=0;
var->hsync_len=0;
var->vsync_len=0;
var->sync=0;
var->vmode=FB_VMODE_NONINTERLACED;
return 0;
}
static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
if(var->xres!=1024)
return -EINVAL;
if(var->yres!=512)
return -EINVAL;
if(var->xres_virtual!=1024)
return -EINVAL;
if(var->yres_virtual!=512)
return -EINVAL;
if(var->xoffset!=0)
return -EINVAL;
if(var->yoffset!=0)
return -EINVAL;
if(var->bits_per_pixel!=16)
return -EINVAL;
if(var->grayscale!=0)
return -EINVAL;
if(var->nonstd!=0)
return -EINVAL;
if(var->activate!=FB_ACTIVATE_NOW)
return -EINVAL;
if(var->pixclock!=0)
return -EINVAL;
if(var->left_margin!=0)
return -EINVAL;
if(var->right_margin!=0)
return -EINVAL;
if(var->hsync_len!=0)
return -EINVAL;
if(var->vsync_len!=0)
return -EINVAL;
if(var->sync!=0)
return -EINVAL;
if(var->vmode!=FB_VMODE_NONINTERLACED)
return -EINVAL;
return 0;
}
static int q40_getcolreg(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *info)
{
/*
* Read a single color register and split it into colors/transparent.
* The return values must have a 16 bit magnitude.
* Return != 0 for invalid regno.
*/
if (regno>=16) return 1;
*transp=0;
*green = ((fbcon_cmap_cfb16[regno]>>11) & 31)<<11;
*red = ((fbcon_cmap_cfb16[regno]>>6) & 31)<<11;
*blue = ((fbcon_cmap_cfb16[regno]) & 63)<<10;
return 0;
}
static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
const struct fb_info *info)
unsigned blue, unsigned transp,
struct fb_info *info)
{
/*
* Set a single color register. The values supplied have a 16 bit
......@@ -191,142 +90,54 @@ static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
* Return != 0 for invalid regno.
*/
red>>=11;
green>>=11;
blue>>=10;
red>>=11;
green>>=11;
blue>>=10;
if (regno < 16) {
fbcon_cmap_cfb16[regno] = ((red & 31) <<6) |
((green & 31) << 11) |
(blue & 63);
info->pseudo_palette[regno] = ((red & 31) <<6) |
((green & 31) << 11) |
(blue & 63);
}
return 0;
}
static int q40fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
#if 1
if (con == info->currcon) /* current console? */
return fb_get_cmap(cmap, kspc, q40_getcolreg, 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(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
#else
printk(KERN_ERR "get cmap not supported\n");
return -EINVAL;
#endif
}
static int q40fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
#if 1
int err;
if (!fb_display[con].cmap.len) { /* no colormap allocated? */
if ((err = fb_alloc_cmap(&fb_display[con].cmap,
1<<fb_display[con].var.bits_per_pixel,
0)))
return err;
}
if (con == info->currcon) /* current console? */
return fb_set_cmap(cmap, kspc, info);
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
#else
printk(KERN_ERR "set cmap not supported\n");
return -EINVAL;
#endif
}
static void q40fb_set_disp(int con, struct fb_info *info)
{
struct fb_fix_screeninfo fix;
struct display *display;
q40fb_get_fix(&fix, con, info);
if (con>=0)
display = &fb_display[con];
else
display = &disp[0];
if (con<0) con=0;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
display->ypanstep = fix.ypanstep;
display->ywrapstep = fix.ywrapstep;
display->can_soft_blank = 0;
display->inverse = 0;
display->line_length = fix.line_length;
display->scrollmode = SCROLL_YREDRAW;
#ifdef FBCON_HAS_CFB16
display->dispsw = &fbcon_cfb16;
disp->dispsw_data = fbcon_cmap_cfb16;
#else
display->dispsw = &fbcon_dummy;
#endif
}
int __init q40fb_init(void)
int q40fb_init(void)
{
if ( !MACH_IS_Q40)
return -ENXIO;
#if 0
fb_info.screen_base = kernel_map(Q40_PHYS_SCREEN_ADDR, 1024*1024,
KERNELMAP_NO_COPYBACK, NULL);
#else
fb_info.screen_base = Q40_PHYS_SCREEN_ADDR; /* mapped in q40/config.c */
#endif
fb_info.changevar=NULL;
strcpy(&fb_info.modename[0],q40fb_name);
fb_info.fontname[0]=0;
fb_info.disp=disp;
fb_info.currcon = -1;
fb_info.switch_con=&q40con_switch;
fb_info.updatevar=&q40con_updatevar;
/* mapped in q40/config.c */
q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR;
fb_info.var = q40fb_var;
fb_info.fix = q40fb_fix;
fb_info.node = NODEV;
fb_info.fbops = &q40fb_ops;
fb_info.flags = FBINFO_FLAG_DEFAULT; /* not as module for now */
fb_info.pseudo_palette = pseudo_palette;
fb_info.screen_base = (char *) q40fb_fix.smem_start;
/* The below feilds will go away !!!! */
fb_info.currcon = -1;
strcpy(fb_info.modename, fb_info.fix.id);
fb_info.disp = &display;
fb_info.switch_con = gen_switch;
fb_info.updatevar = gen_update_var;
fb_alloc_cmap(&fb_info.cmap, 16, 0);
gen_set_disp(-1, &fb_info);
master_outb(3,DISPLAY_CONTROL_REG);
q40fb_get_var(&disp[0].var, 0, &fb_info);
q40fb_set_disp(-1, &fb_info);
master_outb(3, DISPLAY_CONTROL_REG);
if (register_framebuffer(&fb_info) < 0) {
printk(KERN_ERR "unable to register Q40 frame buffer\n");
printk(KERN_ERR "Unable to register Q40 frame buffer\n");
return -EINVAL;
}
printk(KERN_INFO "fb%d: Q40 frame buffer alive and kicking !\n",
GET_FB_IDX(fb_info.node));
return 0;
}
static int q40con_switch(int con, struct fb_info *info)
{
info->currcon=con;
return 0;
}
static int q40con_updatevar(int con, struct fb_info *info)
{
return 0;
}
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");
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