* porting a driver to the new fbdev api - part 2
@ 2005-09-11 12:03 Lior Balkohen
2005-09-12 9:59 ` Antonino A. Daplas
0 siblings, 1 reply; 2+ messages in thread
From: Lior Balkohen @ 2005-09-11 12:03 UTC (permalink / raw)
To: linux-fbdev-devel
ok, apparently no attachments allowed in the list, so i'm sending the
source in plain.
/* Xilleon 220 frame buffer driver
*
* Copyright (C) 2002 MontaVista Software Inc.
*
*/
#include <linux/config.h>
#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/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/fb.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
#include <video/fbcon-cfb16.h>
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
struct x220fb_config {
unsigned int fb_offset;
struct fb_var_screeninfo var;
};
#define X220_MAGIC 0xD8
#define FBIO_X220_CONFIG _IOW (X220_MAGIC, 1, struct x220fb_config)
#define FBIO_X220_WAIT_ACLREQ _IOR (X220_MAGIC, 2, struct fb_var_screeninfo)
#define FBIO_X220_SET_DMS _IOW (X220_MAGIC, 3, int)
// FIXME: just a guess and shouldn't be here
#define X220_MEM_BASE 0
#define X220_MODULE_NAME "X220FB"
#define PFX X220_MODULE_NAME
#define X220_DEBUG
#ifdef X220_DEBUG
#define dbg(format, arg...) \
printk(KERN_DEBUG "%s: " format "\n" , __func__, ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
#define emerg(format, arg...) printk(KERN_EMERG PFX ": " format "\n" , ## arg)
#define CMAPSIZE 16
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
/* command line data, set in x220fb_setup() */
static char __initdata fontname[40] = { 0 };
static int accel = 0;
static int nodms = 0;
static const char *mode_option __initdata = NULL;
struct x220fb_par {
struct fb_var_screeninfo var;
ssize_t fb_size;
int fb_order;
int line_length; // in bytes
};
typedef enum {
IDLE = 0,
WAIT_IN_PROGRESS,
MODE_CHANGE_IN_PROGRESS
} x220fb_state_t;
struct x220fb_info {
struct fb_info_gen gen;
struct x220fb_par curpar;
struct x220fb_par reqpar;
struct display disp;
void * fb_addr_virt;
phys_addr_t fb_addr_phys;
int fake_offset;
x220fb_state_t state;
int dms;
wait_queue_head_t aclreq_wait;
wait_queue_head_t setpar_wait;
struct semaphore ioctl_sem;
struct semaphore setpar_sem;
struct {
unsigned red;
unsigned green;
unsigned blue;
unsigned alpha;
} palette[256];
};
static struct x220fb_info *fb_x220;
static char x220fb_name[16] = X220_MODULE_NAME;
static union {
#ifdef FBCON_HAS_CFB16
u16 cfb16[CMAPSIZE];
#endif
#ifdef FBCON_HAS_CFB24
u32 cfb24[CMAPSIZE];
#endif
#ifdef FBCON_HAS_CFB32
u32 cfb32[CMAPSIZE];
#endif
} fbcon_cmap;
static const struct fb_var_screeninfo x220_default_var = {
640, 480, 640, 480, 0, 0, 16, 0,
{0}, {0}, {0}, {0},
0, FB_ACTIVATE_NOW, -1, -1, 0,
0, 0, 0, 0, 0, 0, 0,
0, FB_VMODE_NONINTERLACED
};
/*
* These are just for documentation purposes - linux fb doesn't
* distinguish between the different broadcast standards.
*/
#define FB_SYNC_PS2 0 // VGA
#define FB_SYNC_HD FB_SYNC_BROADCAST
#define FB_SYNC_NTSC FB_SYNC_BROADCAST
#define FB_SYNC_PAL FB_SYNC_BROADCAST
#define FB_SYNC_SECAM FB_SYNC_BROADCAST
static const struct {
u32 xres;
u32 yres;
u32 vmode; // only holds interlaced vs. progressive info
u32 sync; // only holds PS2 vs. brodcast info
} acl_modes[] = {
{ 640, 480, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
{ 720, 480, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
{ 720, 576, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
{ 800, 600, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
{ 1024, 768, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
{ 1280, 720, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
{ 1920, 1080, FB_VMODE_INTERLACED , FB_SYNC_PS2 },
{ 720, 480, FB_VMODE_INTERLACED , FB_SYNC_HD },
{ 720, 480, FB_VMODE_NONINTERLACED, FB_SYNC_HD },
{ 960, 540, FB_VMODE_NONINTERLACED, FB_SYNC_HD },
{ 1280, 720, FB_VMODE_NONINTERLACED, FB_SYNC_HD },
{ 1920, 1080, FB_VMODE_INTERLACED , FB_SYNC_HD },
{ 720, 480, FB_VMODE_INTERLACED , FB_SYNC_NTSC },
{ 720, 576, FB_VMODE_INTERLACED , FB_SYNC_PAL },
{ 720, 576, FB_VMODE_INTERLACED , FB_SYNC_SECAM }
};
/* Interface used by the world */
int x220fb_init(void);
int x220fb_setup(char *options);
/* Hardware Specific Routines */
static int x220fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, int con, struct fb_info *info);
static void x220fb_detect (void);
static int x220fb_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
struct fb_info_gen *info);
static int x220fb_decode_var (const struct fb_var_screeninfo *var, void *par,
struct fb_info_gen *info);
static int x220fb_encode_var (struct fb_var_screeninfo *var, const void *par,
struct fb_info_gen *info);
static void x220fb_get_par (void *par, struct fb_info_gen *info);
static void x220fb_set_par (const void *par, struct fb_info_gen *info);
static int x220fb_getcolreg (unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *info);
static int x220fb_setcolreg (unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info);
static int x220fb_pan_display (const struct fb_var_screeninfo *var,
struct fb_info_gen *info);
static int x220fb_blank (int blank_mode, struct fb_info_gen *info);
static void x220fb_set_disp (const void *par, struct display *disp,
struct fb_info_gen *info);
/* function table of the above functions */
static struct fb_ops x220fb_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_pan_display: fbgen_pan_display,
fb_ioctl: x220fb_ioctl,
};
/* function table of the above functions */
static struct fbgen_hwswitch x220fb_hwswitch =
{
x220fb_detect,
x220fb_encode_fix,
x220fb_decode_var,
x220fb_encode_var,
x220fb_get_par,
x220fb_set_par,
x220fb_getcolreg,
x220fb_setcolreg,
x220fb_pan_display,
x220fb_blank,
x220fb_set_disp
};
static void set_color_bitfields(struct fb_var_screeninfo *var)
{
switch (var->bits_per_pixel) {
case 16: /* ARGB1555 */
var->transp.offset = 15;
var->transp.length = 1;
var->red.offset = 10;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 5;
var->blue.offset = 0;
var->blue.length = 5;
break;
case 32: /* ARGB 8888 */
var->transp.offset = 24;
var->transp.length = 8;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
break;
}
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
}
static void calc_par(struct x220fb_par *par,
const struct fb_var_screeninfo *var)
{
memset(par, 0, sizeof(struct x220fb_par));
par->line_length =
var->xres_virtual * ((var->bits_per_pixel + 7) >> 3);
par->line_length = (par->line_length + 127) & ~127;
par->fb_size = par->line_length * var->yres_virtual;
par->fb_order = 0;
while (par->fb_size > (PAGE_SIZE * (1 << par->fb_order)))
par->fb_order++;
par->var = *var;
par->var.width = par->var.height = -1;
/* no virtual display support (no panning/scrolling) */
par->var.vmode &= FB_VMODE_MASK;
par->var.xoffset = par->var.yoffset = 0;
par->var.xres_virtual = par->var.xres;
par->var.yres_virtual = par->var.yres;
/* no accels */
par->var.accel_flags = 0;
par->var.sync &= FB_SYNC_BROADCAST;
set_color_bitfields(&par->var);
}
static void x220fb_detect (void)
{
dbg("");
}
static int x220fb_encode_fix(struct fb_fix_screeninfo *fix,
const void* _par,
struct fb_info_gen* _info)
{
struct x220fb_par *par = (struct x220fb_par *) _par;
struct x220fb_info *info = (struct x220fb_info *) _info;
struct fb_var_screeninfo* var = &par->var;
down(&info->setpar_sem);
dbg("");
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, x220fb_name);
fix->smem_start = info->fb_addr_phys;
fix->smem_len = par->fb_size;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
fix->visual = (var->bits_per_pixel <= 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
fix->ywrapstep = 0;
fix->xpanstep = 1;
fix->ypanstep = 1;
fix->line_length = par->line_length;
up(&info->setpar_sem);
return 0;
}
static int x220fb_decode_var(const struct fb_var_screeninfo *var,
void *_par,
struct fb_info_gen *_info)
{
struct x220fb_par *par = (struct x220fb_par *) _par;
struct x220fb_info *info = (struct x220fb_info *) _info;
struct fb_var_screeninfo *curvar = &info->curpar.var;
int i;
dbg("");
if (!info->dms) {
if (var->xres != curvar->xres ||
var->yres != curvar->yres) {
dbg("resolution doesn't match");
return -EINVAL;
}
if ((var->vmode & FB_VMODE_MASK) !=
(curvar->vmode & FB_VMODE_MASK)) {
dbg("interlace mode doesn't match");
return -EINVAL;
}
if ((var->sync & FB_SYNC_BROADCAST) != curvar->sync) {
dbg("sync mode doesn't match");
return -EINVAL;
}
if (var->bits_per_pixel != curvar->bits_per_pixel) {
dbg("color depth doesn't match");
return -EINVAL;
}
}
for (i=0; i < sizeof(acl_modes)/sizeof(acl_modes[0]); i++) {
if (var->xres == acl_modes[i].xres &&
var->yres == acl_modes[i].yres &&
(var->vmode & FB_VMODE_MASK) == acl_modes[i].vmode &&
(var->sync & FB_SYNC_BROADCAST) == acl_modes[i].sync)
break;
}
if (i >= sizeof(acl_modes)/sizeof(acl_modes[0])) {
dbg("unsupported mode: %s %dx%d%c",
(var->sync & FB_SYNC_BROADCAST) ? "Broadcast" : "VGA",
var->xres, var->yres,
(var->vmode & FB_VMODE_INTERLACED) ? 'i' : 'p');
return -EINVAL;
}
if (var->bits_per_pixel != 32 && var->bits_per_pixel != 16) {
dbg("unsupported color depth: %d bpp", var->bits_per_pixel);
return -EINVAL;
}
calc_par(par, var);
if (!info->dms) {
/*
* check memory limit
*/
if (par->line_length * par->var.yres_virtual > par->fb_size) {
dbg("not enough video memory for res %dx%d-%dbpp!",
par->var.xres_virtual, par->var.yres_virtual,
par->var.bits_per_pixel);
return -ENOMEM;
}
}
return 0;
}
static int x220fb_encode_var(struct fb_var_screeninfo *var,
const void *par,
struct fb_info_gen *info)
{
dbg("");
*var = ((struct x220fb_par *)par)->var;
return 0;
}
static void x220fb_set_disp(const void *_par, struct display *disp,
struct fb_info_gen *_info)
{
struct x220fb_par *par = (struct x220fb_par *) _par;
struct x220fb_info *info = (struct x220fb_info *) _info;
down(&info->setpar_sem);
dbg("");
disp->screen_base = (char *)info->fb_addr_virt;
switch (par->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB16
case 16:
disp->dispsw = &fbcon_cfb16;
disp->dispsw_data = fbcon_cmap.cfb16;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
disp->dispsw = &fbcon_cfb24;
disp->dispsw_data = fbcon_cmap.cfb24;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
disp->dispsw = &fbcon_cfb32;
disp->dispsw_data = fbcon_cmap.cfb32;
break;
#endif
default:
disp->dispsw = &fbcon_dummy;
disp->dispsw_data = NULL;
break;
}
up(&info->setpar_sem);
}
/*
* Blank the display.
*
* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off
*/
static int x220fb_blank(int mode, struct fb_info_gen *_info)
{
/* not supported */
dbg("");
return -EINVAL;
}
/* get current video mode */
static void x220fb_get_par (void *_par, struct fb_info_gen *_info)
{
struct x220fb_par *par = (struct x220fb_par *) _par;
struct x220fb_info *info = (struct x220fb_info *) _info;
down(&info->setpar_sem);
dbg("");
*par = info->curpar;
up(&info->setpar_sem);
}
static void x220fb_set_par(const void *_par, struct fb_info_gen *_info)
{
struct x220fb_par *par = (struct x220fb_par *) _par;
struct x220fb_info *info = (struct x220fb_info *) _info;
struct fb_var_screeninfo *curvar = &info->curpar.var;
struct fb_var_screeninfo *newvar = &par->var;
DECLARE_WAITQUEUE(wait, current);
dbg("%dx%d-%dbpp", newvar->xres, newvar->yres, newvar->bits_per_pixel);
if (!info->dms)
return;
down(&info->setpar_sem);
if (newvar->xres != curvar->xres ||
newvar->yres != curvar->yres ||
newvar->bits_per_pixel != curvar->bits_per_pixel) {
if (info->state != WAIT_IN_PROGRESS) {
dbg("invalid state (no daemon listening?)");
*par = info->curpar;
up(&info->setpar_sem);
return;
}
/* wakeup ACL daemon waiting for a request... */
if (waitqueue_active(&info->aclreq_wait)) {
dbg("waking ACL daemon");
wake_up(&info->aclreq_wait);
}
/* and give the daemon the requested par */
info->reqpar = *par;
dbg("waiting for ACL daemon to program mode");
/* now sleep waiting for ACL to complete the mode */
add_wait_queue(&info->setpar_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
schedule();
remove_wait_queue(&info->setpar_wait, &wait);
set_current_state(TASK_RUNNING);
dbg("ACL daemon done programming mode");
/*
* the requested mode may not have succeeded,
* make sure we return the actual current mode
* to the caller.
*/
*par = info->curpar;
}
up(&info->setpar_sem);
}
static int x220fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, int con, struct fb_info *_info)
{
int fbidx = GET_FB_IDX(inode->i_rdev);
int dms_enb_dis, ret = 0;
struct x220fb_info *info = (struct x220fb_info *) _info;
struct fb_var_screeninfo *var;
struct x220fb_par *curpar = &info->curpar;
struct x220fb_config cfg;
DECLARE_WAITQUEUE(wait, current);
extern int set_all_vcs(int, struct fb_ops *,
struct fb_var_screeninfo *var,
struct fb_info *);
/*
* this mutex prevents reentrancy while sleeping in
* WAIT_ACLREQ.
*/
down(&info->ioctl_sem);
dbg("");
switch (cmd) {
case FBIO_X220_SET_DMS:
/*
* changing the DMS flag at weird times can
* screw-up the mode-change state machine
* (it should ony be done when info->state = IDLE),
* but since only the daemon uses these custom
* ioctls, and we must trust the daemon, we'll
* allow it always.
*/
if (get_user(dms_enb_dis, (int *)(arg))) {
ret = -EFAULT;
break;
}
info->dms = dms_enb_dis;
info("Dynamic Mode Selection is %s",
info->dms ? "ON" : "OFF");
break;
case FBIO_X220_CONFIG:
if (info->dms && info->state != MODE_CHANGE_IN_PROGRESS) {
dbg("hey daemon, you're doing something stupid!");
ret = -EINVAL;
break;
}
if (copy_from_user(&cfg, (void *)arg,
sizeof(struct x220fb_config))) {
err("fault in copy_from_user");
ret = -EFAULT;
break;
}
if (info->fake_offset) {
free_pages((unsigned long)info->fb_addr_virt,
curpar->fb_order);
info->fake_offset = 0;
} else if (info->fb_addr_virt)
iounmap(info->fb_addr_virt);
var = &cfg.var;
calc_par(curpar, var);
info->fb_addr_phys = X220_MEM_BASE + cfg.fb_offset;
info->fb_addr_virt = ioremap(info->fb_addr_phys,
curpar->fb_size);
if (info->dms) {
/* wakeup FB app waiting for set_par to complete */
if (waitqueue_active(&info->setpar_wait)) {
dbg("CONFIG: waking FB app");
wake_up(&info->setpar_wait);
}
} else {
if (var->activate & FB_ACTIVATE_ALL)
set_all_vcs(fbidx, _info->fbops,
var, _info);
else
_info->fbops->fb_set_var(var,
PROC_CONSOLE(_info),
_info);
}
// mode change cycle is complete, back to IDLE
info->state = IDLE;
info("CONFIG: FB at 0x%08x, mapped to %p, size %d",
(u32)info->fb_addr_phys,
info->fb_addr_virt,
(int)curpar->fb_size);
info("CONFIG: mode set to %dx%d-%dbpp",
var->xres, var->yres, var->bits_per_pixel);
break;
case FBIO_X220_WAIT_ACLREQ:
if (info->dms) {
if (info->state != IDLE) {
dbg("hey daemon, you're doing "
"something stupid!");
ret = -EINVAL;
break;
}
dbg("WAIT_ACLREQ: waiting...");
info->state = WAIT_IN_PROGRESS;
add_wait_queue(&info->aclreq_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
schedule();
remove_wait_queue(&info->aclreq_wait, &wait);
set_current_state(TASK_RUNNING);
if (signal_pending(current)) {
info->state = IDLE;
ret = -ERESTARTSYS;
break;
}
dbg("WAIT_ACLREQ: got a request");
info->state = MODE_CHANGE_IN_PROGRESS;
/*
* a framebuffer app has issued a set var, waking
* us up. Return the requested var (to ACL daemon).
*/
if (copy_to_user((void *) arg,
&info->reqpar.var,
sizeof(struct fb_var_screeninfo))) {
err("fault in copy_to_user");
ret = -EFAULT;
}
} else {
ret = -EINVAL;
}
break;
default:
ret = -EINVAL;
}
up(&info->ioctl_sem);
return ret;
}
static int x220fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *_info)
{
struct x220fb_info *info = (struct x220fb_info *) _info;
//dbg("");
if (regno > 255)
return 1;
*red = info->palette[regno].red << 10;
*green = info->palette[regno].green << 10;
*blue = info->palette[regno].blue << 10;
*transp = info->palette[regno].alpha << 10;
return 0;
}
static int x220fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *_info)
{
struct x220fb_info *info = (struct x220fb_info *) _info;
struct x220fb_par* par = &info->curpar;
//dbg("");
if (regno > 255)
return -EINVAL;
info->palette[regno].red = red >> 10;
info->palette[regno].green = green >> 10;
info->palette[regno].blue = blue >> 10;
info->palette[regno].alpha = transp >> 10;
switch (par->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB16
case 16:
if(regno < CMAPSIZE)
fbcon_cmap.cfb16[regno] =
((red & 0xf800) >> 0) |
((green & 0xf800) >> 5) |
((blue & 0xf800) >> 11);
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
if (regno < CMAPSIZE)
fbcon_cmap.cfb24[regno] =
((red & 0xff00) << 8) |
((green & 0xff00)) |
((blue & 0xff00) >> 8);
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
if(regno < CMAPSIZE)
// FIXME: what about transp
fbcon_cmap.cfb32[regno] =
((red & 0xff00) >> 8) |
((green & 0xff00)) |
((blue & 0xff00) << 8);
break;
#endif
default:
break;
}
return 0;
}
static int x220fb_pan_display (const struct fb_var_screeninfo *var,
struct fb_info_gen *info)
{
/* not supported */
dbg("");
return -EINVAL;
}
/*
* Initialisation
*/
int __init x220fb_init(void)
{
struct x220fb_info *p = NULL;
struct fb_var_screeninfo *var;
fb_x220 = p =
(struct x220fb_info *) kmalloc(sizeof(*p), GFP_ATOMIC);
if(p==NULL)
return -ENOMEM;
memset(p, 0, sizeof(*p));
init_waitqueue_head(&p->aclreq_wait);
init_waitqueue_head(&p->setpar_wait);
init_MUTEX(&p->setpar_sem);
init_MUTEX(&p->ioctl_sem);
info("Xilleon 220 Framebuffer Driver");
/* set up a few more things, register framebuffer driver etc */
p->gen.parsize = sizeof (struct x220fb_par);
p->gen.fbhw = &x220fb_hwswitch;
strcpy(p->gen.info.modename, "ATI ");
strcat(p->gen.info.modename, x220fb_name);
p->gen.info.changevar = NULL;
p->gen.info.node = -1;
p->gen.info.fbops = &x220fb_ops;
p->gen.info.disp = &p->disp;
p->gen.info.switch_con = &fbgen_switch;
p->gen.info.updatevar = &fbgen_update_var;
p->gen.info.blank = &fbgen_blank;
p->gen.info.flags = FBINFO_FLAG_DEFAULT;
calc_par(&p->curpar, &x220_default_var);
var = &p->curpar.var;
/* TODO: explain this crap */
p->fb_addr_virt = (void *)__get_free_pages(GFP_KERNEL,
p->curpar.fb_order);
p->fb_addr_phys = virt_to_phys(p->fb_addr_virt);
p->fake_offset = 1;
info("Initial framebuffer at 0x%08x, mapped to %p, size %d",
(u32)p->fb_addr_phys,
p->fb_addr_virt,
(int)p->curpar.fb_size);
if (fbgen_do_set_var(&p->curpar.var, 1, &p->gen)) {
err("boot video mode failed");
goto ret_enxio;
}
p->disp.var = p->curpar.var;
fbgen_set_disp(-1, &p->gen);
fbgen_install_cmap(0, &p->gen);
if (register_framebuffer(&p->gen.info) < 0) {
goto ret_enxio;
}
if (!nodms)
p->dms = 1;
return 0;
ret_enxio:
kfree(p);
iounmap(p->fb_addr_virt);
return -ENXIO;
}
#ifdef MODULE
static void __exit x220fb_exit(void)
{
unregister_framebuffer(&(fb_x220->gen.info));
iounmap(fb_x220->fb_addr_virt);
kfree(fb_x220);
}
module_init(x220fb_init);
module_exit(x220fb_exit);
MODULE_PARM(font, "s");
MODULE_PARM_DESC(font, "Specifies a compiled-in font (default=none)");
MODULE_PARM(accel, "i");
MODULE_PARM_DESC(accel, "Enables hardware acceleration (default=0)");
MODULE_PARM(nodms, "i");
MODULE_PARM_DESC(nodms, "Disables dynamic mode selection (default=0)");
#else
int x220fb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 1;
for (this_opt = strtok(options, ","); this_opt;
this_opt = strtok(NULL, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
strcpy(fontname, this_opt+5);
} else if (!strncmp(this_opt, "accel", 5)) {
accel = 1;
} else if (!strncmp(this_opt, "nodms", 3)) {
nodms = 1;
} else {
mode_option = this_opt;
}
}
return 0;
}
#endif /* MODULE */
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: porting a driver to the new fbdev api - part 2
2005-09-11 12:03 porting a driver to the new fbdev api - part 2 Lior Balkohen
@ 2005-09-12 9:59 ` Antonino A. Daplas
0 siblings, 0 replies; 2+ messages in thread
From: Antonino A. Daplas @ 2005-09-12 9:59 UTC (permalink / raw)
To: linux-fbdev-devel, balkohen
Lior Balkohen wrote:
Just a few suggestions. If you have more specific questions, feel free
to ask.
> ok, apparently no attachments allowed in the list, so i'm sending the
> source in plain.
>
> /* Xilleon 220 frame buffer driver
> *
> * Copyright (C) 2002 MontaVista Software Inc.
> *
> */
>
> #include <linux/config.h>
> #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/slab.h>
> #include <linux/vmalloc.h>
> #include <linux/delay.h>
> #include <linux/interrupt.h>
> #include <asm/uaccess.h>
> #include <linux/fb.h>
> #include <linux/ioctl.h>
> #include <linux/init.h>
> #include <linux/pci.h>
> #include <asm/io.h>
>
> #include <video/fbcon.h>
> #include <video/fbcon-mfb.h>
> #include <video/fbcon-cfb16.h>
> #include <video/fbcon-cfb24.h>
> #include <video/fbcon-cfb32.h>
video/fbcon*.h are not needed.
>
> struct x220fb_config {
> unsigned int fb_offset;
> struct fb_var_screeninfo var;
> };
>
> #define X220_MAGIC 0xD8
> #define FBIO_X220_CONFIG _IOW (X220_MAGIC, 1, struct x220fb_config)
> #define FBIO_X220_WAIT_ACLREQ _IOR (X220_MAGIC, 2, struct fb_var_screeninfo)
> #define FBIO_X220_SET_DMS _IOW (X220_MAGIC, 3, int)
>
> // FIXME: just a guess and shouldn't be here
> #define X220_MEM_BASE 0
>
> #define X220_MODULE_NAME "X220FB"
> #define PFX X220_MODULE_NAME
>
> #define X220_DEBUG
>
> #ifdef X220_DEBUG
> #define dbg(format, arg...) \
> printk(KERN_DEBUG "%s: " format "\n" , __func__, ## arg)
> #else
> #define dbg(format, arg...) do {} while (0)
> #endif
> #define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
> #define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
> #define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
> #define emerg(format, arg...) printk(KERN_EMERG PFX ": " format "\n" , ## arg)
>
> #define CMAPSIZE 16
> #define arraysize(x) (sizeof(x)/sizeof(*(x)))
>
> /* command line data, set in x220fb_setup() */
> static char __initdata fontname[40] = { 0 };
> static int accel = 0;
> static int nodms = 0;
>
> static const char *mode_option __initdata = NULL;
>
> struct x220fb_par {
> struct fb_var_screeninfo var;
>
> ssize_t fb_size;
> int fb_order;
>
> int line_length; // in bytes
> };
>
> typedef enum {
> IDLE = 0,
> WAIT_IN_PROGRESS,
> MODE_CHANGE_IN_PROGRESS
> } x220fb_state_t;
>
>
> struct x220fb_info {
> struct fb_info_gen gen;
struct fb_info_gen is gone
> struct x220fb_par curpar;
> struct x220fb_par reqpar;
> struct display disp;
>
> void * fb_addr_virt;
> phys_addr_t fb_addr_phys;
>
> int fake_offset;
> x220fb_state_t state;
> int dms;
>
> wait_queue_head_t aclreq_wait;
> wait_queue_head_t setpar_wait;
> struct semaphore ioctl_sem;
> struct semaphore setpar_sem;
>
> struct {
> unsigned red;
> unsigned green;
> unsigned blue;
> unsigned alpha;
> } palette[256];
> };
You can combine all private data into one.
>
> static struct x220fb_info *fb_x220;
>
> static char x220fb_name[16] = X220_MODULE_NAME;
>
> static union {
> #ifdef FBCON_HAS_CFB16
> u16 cfb16[CMAPSIZE];
> #endif
> #ifdef FBCON_HAS_CFB24
> u32 cfb24[CMAPSIZE];
> #endif
> #ifdef FBCON_HAS_CFB32
> u32 cfb32[CMAPSIZE];
> #endif
> } fbcon_cmap;
>
You don't need the above.
> static const struct fb_var_screeninfo x220_default_var = {
> 640, 480, 640, 480, 0, 0, 16, 0,
> {0}, {0}, {0}, {0},
> 0, FB_ACTIVATE_NOW, -1, -1, 0,
> 0, 0, 0, 0, 0, 0, 0,
> 0, FB_VMODE_NONINTERLACED
> };
>
> /*
> * These are just for documentation purposes - linux fb doesn't
> * distinguish between the different broadcast standards.
> */
> #define FB_SYNC_PS2 0 // VGA
> #define FB_SYNC_HD FB_SYNC_BROADCAST
> #define FB_SYNC_NTSC FB_SYNC_BROADCAST
> #define FB_SYNC_PAL FB_SYNC_BROADCAST
> #define FB_SYNC_SECAM FB_SYNC_BROADCAST
>
> static const struct {
> u32 xres;
> u32 yres;
> u32 vmode; // only holds interlaced vs. progressive info
> u32 sync; // only holds PS2 vs. brodcast info
> } acl_modes[] = {
> { 640, 480, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
> { 720, 480, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
> { 720, 576, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
> { 800, 600, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
> { 1024, 768, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
> { 1280, 720, FB_VMODE_NONINTERLACED, FB_SYNC_PS2 },
> { 1920, 1080, FB_VMODE_INTERLACED , FB_SYNC_PS2 },
> { 720, 480, FB_VMODE_INTERLACED , FB_SYNC_HD },
> { 720, 480, FB_VMODE_NONINTERLACED, FB_SYNC_HD },
> { 960, 540, FB_VMODE_NONINTERLACED, FB_SYNC_HD },
> { 1280, 720, FB_VMODE_NONINTERLACED, FB_SYNC_HD },
> { 1920, 1080, FB_VMODE_INTERLACED , FB_SYNC_HD },
> { 720, 480, FB_VMODE_INTERLACED , FB_SYNC_NTSC },
> { 720, 576, FB_VMODE_INTERLACED , FB_SYNC_PAL },
> { 720, 576, FB_VMODE_INTERLACED , FB_SYNC_SECAM }
> };
>
>
> /* Interface used by the world */
> int x220fb_init(void);
> int x220fb_setup(char *options);
fb_setup is gone.
>
> /* Hardware Specific Routines */
> static int x220fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
> u_long arg, int con, struct fb_info *info);
> static void x220fb_detect (void);
fb_detect is gone
> static int x220fb_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
> struct fb_info_gen *info);
> static int x220fb_decode_var (const struct fb_var_screeninfo *var, void *par,
> struct fb_info_gen *info);
> static int x220fb_encode_var (struct fb_var_screeninfo *var, const void *par,
> struct fb_info_gen *info);
The above 3 are gone
> static void x220fb_get_par (void *par, struct fb_info_gen *info);
The above is gone
> static void x220fb_set_par (const void *par, struct fb_info_gen *info);
This is now int fb_set_par(struct fb_info);
> static int x220fb_getcolreg (unsigned regno, unsigned *red, unsigned *green,
> unsigned *blue, unsigned *transp,
> struct fb_info *info);
fb_getcolreg is gone.
> static int x220fb_setcolreg (unsigned regno, unsigned red, unsigned green,
> unsigned blue, unsigned transp,
> struct fb_info *info);
> static int x220fb_pan_display (const struct fb_var_screeninfo *var,
> struct fb_info_gen *info);
> static int x220fb_blank (int blank_mode, struct fb_info_gen *info);
You need the above 3. Change struct fb_info_gen to fb_info.
> static void x220fb_set_disp (const void *par, struct display *disp,
> struct fb_info_gen *info);
>
fb_set_disp is gone.
> /* function table of the above functions */
> static struct fb_ops x220fb_ops = {
> owner: THIS_MODULE,
> fb_get_fix: fbgen_get_fix,
> fb_get_var: fbgen_get_var,
> fb_set_var: fbgen_set_var,
fb_set_var is split into two:
fb_check_var() - check/round up values in struct fb_var_screeninfo to one that
fits hardware
fb_set_par() - initialize hardware based on the contents of struct fb_info.var;
> fb_get_cmap: fbgen_get_cmap,
fb_get_cmap() is gone.
> fb_set_cmap: fbgen_set_cmap,
fb_get_cmap() is replaced by fb_set_colreg. However, an optional fb_set_cmap()
is recently added to 2.6 kernels. You may choose not to provide one.
> fb_pan_display: fbgen_pan_display,
> fb_ioctl: x220fb_ioctl,
You need additional 4 hooks (required)
fb_imageblit
fb_copyarea
fb_fillrect
fb_cursor
You can use the provided generic functions for the above:
cfb_imageblit, cfb_copyarea, cfb_fillrect, soft_cursor.
> };
>
> /* function table of the above functions */
> static struct fbgen_hwswitch x220fb_hwswitch =
> {
> x220fb_detect,
> x220fb_encode_fix,
> x220fb_decode_var,
> x220fb_encode_var,
> x220fb_get_par,
> x220fb_set_par,
> x220fb_getcolreg,
> x220fb_setcolreg,
> x220fb_pan_display,
> x220fb_blank,
> x220fb_set_disp
> };
fb_hwswitch is gone.
>
>
> static void set_color_bitfields(struct fb_var_screeninfo *var)
> {
> switch (var->bits_per_pixel) {
> case 16: /* ARGB1555 */
> var->transp.offset = 15;
> var->transp.length = 1;
> var->red.offset = 10;
> var->red.length = 5;
> var->green.offset = 5;
> var->green.length = 5;
> var->blue.offset = 0;
> var->blue.length = 5;
> break;
> case 32: /* ARGB 8888 */
> var->transp.offset = 24;
> var->transp.length = 8;
> var->red.offset = 16;
> var->red.length = 8;
> var->green.offset = 8;
> var->green.length = 8;
> var->blue.offset = 0;
> var->blue.length = 8;
> break;
> }
>
> var->red.msb_right = 0;
> var->green.msb_right = 0;
> var->blue.msb_right = 0;
> var->transp.msb_right = 0;
> }
>
>
You can reuse set_color_bitfields as part of fb_check_var().
> static void calc_par(struct x220fb_par *par,
> const struct fb_var_screeninfo *var)
> {
> memset(par, 0, sizeof(struct x220fb_par));
>
> par->line_length =
> var->xres_virtual * ((var->bits_per_pixel + 7) >> 3);
> par->line_length = (par->line_length + 127) & ~127;
>
> par->fb_size = par->line_length * var->yres_virtual;
>
> par->fb_order = 0;
> while (par->fb_size > (PAGE_SIZE * (1 << par->fb_order)))
> par->fb_order++;
>
> par->var = *var;
>
> par->var.width = par->var.height = -1;
> /* no virtual display support (no panning/scrolling) */
> par->var.vmode &= FB_VMODE_MASK;
> par->var.xoffset = par->var.yoffset = 0;
> par->var.xres_virtual = par->var.xres;
> par->var.yres_virtual = par->var.yres;
> /* no accels */
> par->var.accel_flags = 0;
> par->var.sync &= FB_SYNC_BROADCAST;
>
> set_color_bitfields(&par->var);
> }
>
You can reuse calc_par() as part of fb_set_par().
>
> static void x220fb_detect (void)
> {
> dbg("");
> }
>
fb_detect is not needed.
>
> static int x220fb_encode_fix(struct fb_fix_screeninfo *fix,
> const void* _par,
> struct fb_info_gen* _info)
> {
> struct x220fb_par *par = (struct x220fb_par *) _par;
> struct x220fb_info *info = (struct x220fb_info *) _info;
> struct fb_var_screeninfo* var = &par->var;
>
> down(&info->setpar_sem);
>
> dbg("");
>
> memset(fix, 0, sizeof(struct fb_fix_screeninfo));
> strcpy(fix->id, x220fb_name);
>
> fix->smem_start = info->fb_addr_phys;
> fix->smem_len = par->fb_size;
> fix->type = FB_TYPE_PACKED_PIXELS;
> fix->type_aux = 0;
> fix->visual = (var->bits_per_pixel <= 8) ?
> FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
> fix->ywrapstep = 0;
> fix->xpanstep = 1;
> fix->ypanstep = 1;
> fix->line_length = par->line_length;
>
> up(&info->setpar_sem);
>
> return 0;
> }
>
You can reuse encode_fix as part of fb_set_par().
>
>
> static int x220fb_decode_var(const struct fb_var_screeninfo *var,
> void *_par,
> struct fb_info_gen *_info)
> {
> struct x220fb_par *par = (struct x220fb_par *) _par;
> struct x220fb_info *info = (struct x220fb_info *) _info;
> struct fb_var_screeninfo *curvar = &info->curpar.var;
> int i;
>
> dbg("");
>
> if (!info->dms) {
> if (var->xres != curvar->xres ||
> var->yres != curvar->yres) {
> dbg("resolution doesn't match");
> return -EINVAL;
> }
>
> if ((var->vmode & FB_VMODE_MASK) !=
> (curvar->vmode & FB_VMODE_MASK)) {
> dbg("interlace mode doesn't match");
> return -EINVAL;
> }
>
> if ((var->sync & FB_SYNC_BROADCAST) != curvar->sync) {
> dbg("sync mode doesn't match");
> return -EINVAL;
> }
>
> if (var->bits_per_pixel != curvar->bits_per_pixel) {
> dbg("color depth doesn't match");
> return -EINVAL;
> }
> }
>
> for (i=0; i < sizeof(acl_modes)/sizeof(acl_modes[0]); i++) {
> if (var->xres == acl_modes[i].xres &&
> var->yres == acl_modes[i].yres &&
> (var->vmode & FB_VMODE_MASK) == acl_modes[i].vmode &&
> (var->sync & FB_SYNC_BROADCAST) == acl_modes[i].sync)
> break;
> }
> if (i >= sizeof(acl_modes)/sizeof(acl_modes[0])) {
> dbg("unsupported mode: %s %dx%d%c",
> (var->sync & FB_SYNC_BROADCAST) ? "Broadcast" : "VGA",
> var->xres, var->yres,
> (var->vmode & FB_VMODE_INTERLACED) ? 'i' : 'p');
> return -EINVAL;
> }
>
> if (var->bits_per_pixel != 32 && var->bits_per_pixel != 16) {
> dbg("unsupported color depth: %d bpp", var->bits_per_pixel);
> return -EINVAL;
> }
>
> calc_par(par, var);
>
> if (!info->dms) {
> /*
> * check memory limit
> */
> if (par->line_length * par->var.yres_virtual > par->fb_size) {
> dbg("not enough video memory for res %dx%d-%dbpp!",
> par->var.xres_virtual, par->var.yres_virtual,
> par->var.bits_per_pixel);
> return -ENOMEM;
> }
> }
>
> return 0;
> }
>
You may reuse decode_var as part of fb_check_var().
>
> static int x220fb_encode_var(struct fb_var_screeninfo *var,
> const void *par,
> struct fb_info_gen *info)
> {
> dbg("");
>
> *var = ((struct x220fb_par *)par)->var;
> return 0;
> }
>
>
> static void x220fb_set_disp(const void *_par, struct display *disp,
> struct fb_info_gen *_info)
> {
> struct x220fb_par *par = (struct x220fb_par *) _par;
> struct x220fb_info *info = (struct x220fb_info *) _info;
>
> down(&info->setpar_sem);
>
> dbg("");
>
> disp->screen_base = (char *)info->fb_addr_virt;
>
> switch (par->var.bits_per_pixel) {
> #ifdef FBCON_HAS_CFB16
> case 16:
> disp->dispsw = &fbcon_cfb16;
> disp->dispsw_data = fbcon_cmap.cfb16;
> break;
> #endif
> #ifdef FBCON_HAS_CFB24
> case 24:
> disp->dispsw = &fbcon_cfb24;
> disp->dispsw_data = fbcon_cmap.cfb24;
> break;
> #endif
> #ifdef FBCON_HAS_CFB32
> case 32:
> disp->dispsw = &fbcon_cfb32;
> disp->dispsw_data = fbcon_cmap.cfb32;
> break;
> #endif
> default:
> disp->dispsw = &fbcon_dummy;
> disp->dispsw_data = NULL;
> break;
> }
>
> up(&info->setpar_sem);
> }
>
You don't need fb_set_disp.
>
>
> /*
> * Blank the display.
> *
> * 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off
> */
> static int x220fb_blank(int mode, struct fb_info_gen *_info)
> {
> /* not supported */
> dbg("");
> return -EINVAL;
> }
>
>
> /* get current video mode */
> static void x220fb_get_par (void *_par, struct fb_info_gen *_info)
> {
> struct x220fb_par *par = (struct x220fb_par *) _par;
> struct x220fb_info *info = (struct x220fb_info *) _info;
>
> down(&info->setpar_sem);
> dbg("");
> *par = info->curpar;
> up(&info->setpar_sem);
> }
>
You don't need the above.
>
> static void x220fb_set_par(const void *_par, struct fb_info_gen *_info)
> {
> struct x220fb_par *par = (struct x220fb_par *) _par;
> struct x220fb_info *info = (struct x220fb_info *) _info;
> struct fb_var_screeninfo *curvar = &info->curpar.var;
> struct fb_var_screeninfo *newvar = &par->var;
> DECLARE_WAITQUEUE(wait, current);
>
> dbg("%dx%d-%dbpp", newvar->xres, newvar->yres, newvar->bits_per_pixel);
>
> if (!info->dms)
> return;
>
> down(&info->setpar_sem);
>
> if (newvar->xres != curvar->xres ||
> newvar->yres != curvar->yres ||
> newvar->bits_per_pixel != curvar->bits_per_pixel) {
>
> if (info->state != WAIT_IN_PROGRESS) {
> dbg("invalid state (no daemon listening?)");
> *par = info->curpar;
> up(&info->setpar_sem);
> return;
> }
>
> /* wakeup ACL daemon waiting for a request... */
> if (waitqueue_active(&info->aclreq_wait)) {
> dbg("waking ACL daemon");
> wake_up(&info->aclreq_wait);
> }
>
> /* and give the daemon the requested par */
> info->reqpar = *par;
>
> dbg("waiting for ACL daemon to program mode");
>
> /* now sleep waiting for ACL to complete the mode */
> add_wait_queue(&info->setpar_wait, &wait);
> __set_current_state(TASK_INTERRUPTIBLE);
> schedule();
> remove_wait_queue(&info->setpar_wait, &wait);
> set_current_state(TASK_RUNNING);
> dbg("ACL daemon done programming mode");
>
> /*
> * the requested mode may not have succeeded,
> * make sure we return the actual current mode
> * to the caller.
> */
> *par = info->curpar;
> }
>
> up(&info->setpar_sem);
> }
>
You need the above. You probably don't need the semaphore as
almost all fb_functions are serialized by the console semaphore.
>
> static int x220fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
> u_long arg, int con, struct fb_info *_info)
> {
> int fbidx = GET_FB_IDX(inode->i_rdev);
> int dms_enb_dis, ret = 0;
> struct x220fb_info *info = (struct x220fb_info *) _info;
> struct fb_var_screeninfo *var;
> struct x220fb_par *curpar = &info->curpar;
> struct x220fb_config cfg;
> DECLARE_WAITQUEUE(wait, current);
> extern int set_all_vcs(int, struct fb_ops *,
> struct fb_var_screeninfo *var,
> struct fb_info *);
>
> /*
> * this mutex prevents reentrancy while sleeping in
> * WAIT_ACLREQ.
> */
> down(&info->ioctl_sem);
>
> dbg("");
>
> switch (cmd) {
> case FBIO_X220_SET_DMS:
> /*
> * changing the DMS flag at weird times can
> * screw-up the mode-change state machine
> * (it should ony be done when info->state = IDLE),
> * but since only the daemon uses these custom
> * ioctls, and we must trust the daemon, we'll
> * allow it always.
> */
> if (get_user(dms_enb_dis, (int *)(arg))) {
> ret = -EFAULT;
> break;
> }
> info->dms = dms_enb_dis;
> info("Dynamic Mode Selection is %s",
> info->dms ? "ON" : "OFF");
> break;
> case FBIO_X220_CONFIG:
> if (info->dms && info->state != MODE_CHANGE_IN_PROGRESS) {
> dbg("hey daemon, you're doing something stupid!");
> ret = -EINVAL;
> break;
> }
>
> if (copy_from_user(&cfg, (void *)arg,
> sizeof(struct x220fb_config))) {
> err("fault in copy_from_user");
> ret = -EFAULT;
> break;
> }
>
> if (info->fake_offset) {
> free_pages((unsigned long)info->fb_addr_virt,
> curpar->fb_order);
> info->fake_offset = 0;
> } else if (info->fb_addr_virt)
> iounmap(info->fb_addr_virt);
>
> var = &cfg.var;
> calc_par(curpar, var);
>
> info->fb_addr_phys = X220_MEM_BASE + cfg.fb_offset;
> info->fb_addr_virt = ioremap(info->fb_addr_phys,
> curpar->fb_size);
> if (info->dms) {
> /* wakeup FB app waiting for set_par to complete */
> if (waitqueue_active(&info->setpar_wait)) {
> dbg("CONFIG: waking FB app");
> wake_up(&info->setpar_wait);
> }
> } else {
> if (var->activate & FB_ACTIVATE_ALL)
> set_all_vcs(fbidx, _info->fbops,
> var, _info);
> else
> _info->fbops->fb_set_var(var,
> PROC_CONSOLE(_info),
> _info);
> }
>
> // mode change cycle is complete, back to IDLE
> info->state = IDLE;
> info("CONFIG: FB at 0x%08x, mapped to %p, size %d",
> (u32)info->fb_addr_phys,
> info->fb_addr_virt,
> (int)curpar->fb_size);
> info("CONFIG: mode set to %dx%d-%dbpp",
> var->xres, var->yres, var->bits_per_pixel);
> break;
> case FBIO_X220_WAIT_ACLREQ:
> if (info->dms) {
> if (info->state != IDLE) {
> dbg("hey daemon, you're doing "
> "something stupid!");
> ret = -EINVAL;
> break;
> }
>
> dbg("WAIT_ACLREQ: waiting...");
> info->state = WAIT_IN_PROGRESS;
> add_wait_queue(&info->aclreq_wait, &wait);
> __set_current_state(TASK_INTERRUPTIBLE);
> schedule();
> remove_wait_queue(&info->aclreq_wait, &wait);
> set_current_state(TASK_RUNNING);
> if (signal_pending(current)) {
> info->state = IDLE;
> ret = -ERESTARTSYS;
> break;
> }
> dbg("WAIT_ACLREQ: got a request");
>
> info->state = MODE_CHANGE_IN_PROGRESS;
>
> /*
> * a framebuffer app has issued a set var, waking
> * us up. Return the requested var (to ACL daemon).
> */
> if (copy_to_user((void *) arg,
> &info->reqpar.var,
> sizeof(struct fb_var_screeninfo))) {
> err("fault in copy_to_user");
> ret = -EFAULT;
> }
> } else {
> ret = -EINVAL;
> }
>
> break;
> default:
> ret = -EINVAL;
> }
>
> up(&info->ioctl_sem);
> return ret;
> }
>
fb_ioctl, as always, is optional.
>
> static int x220fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
> unsigned *blue, unsigned *transp,
> struct fb_info *_info)
> {
> struct x220fb_info *info = (struct x220fb_info *) _info;
>
> //dbg("");
>
> if (regno > 255)
> return 1;
>
> *red = info->palette[regno].red << 10;
> *green = info->palette[regno].green << 10;
> *blue = info->palette[regno].blue << 10;
> *transp = info->palette[regno].alpha << 10;
>
> return 0;
> }
>
You don't need the above.
>
> static int x220fb_setcolreg(unsigned regno, unsigned red, unsigned green,
> unsigned blue, unsigned transp,
> struct fb_info *_info)
> {
> struct x220fb_info *info = (struct x220fb_info *) _info;
> struct x220fb_par* par = &info->curpar;
>
> //dbg("");
>
> if (regno > 255)
> return -EINVAL;
>
> info->palette[regno].red = red >> 10;
> info->palette[regno].green = green >> 10;
> info->palette[regno].blue = blue >> 10;
> info->palette[regno].alpha = transp >> 10;
>
You need to write these to the hardware palette before exiting.
> switch (par->var.bits_per_pixel) {
> #ifdef FBCON_HAS_CFB16
> case 16:
> if(regno < CMAPSIZE)
> fbcon_cmap.cfb16[regno] =
> ((red & 0xf800) >> 0) |
> ((green & 0xf800) >> 5) |
> ((blue & 0xf800) >> 11);
> break;
> #endif
> #ifdef FBCON_HAS_CFB24
> case 24:
> if (regno < CMAPSIZE)
> fbcon_cmap.cfb24[regno] =
> ((red & 0xff00) << 8) |
> ((green & 0xff00)) |
> ((blue & 0xff00) >> 8);
> break;
> #endif
> #ifdef FBCON_HAS_CFB32
> case 32:
> if(regno < CMAPSIZE)
> // FIXME: what about transp
> fbcon_cmap.cfb32[regno] =
> ((red & 0xff00) >> 8) |
> ((green & 0xff00)) |
> ((blue & 0xff00) << 8);
> break;
> #endif
> default:
> break;
> }
>
> return 0;
> }
>
You need the above, but needs a little modification. Write the
color values in info->pseudo_palette instead. And no need for the
#ifdef/#endif
>
> static int x220fb_pan_display (const struct fb_var_screeninfo *var,
> struct fb_info_gen *info)
> {
> /* not supported */
> dbg("");
>
> return -EINVAL;
> }
>
>
> /*
> * Initialisation
> */
> int __init x220fb_init(void)
> {
> struct x220fb_info *p = NULL;
> struct fb_var_screeninfo *var;
>
> fb_x220 = p =
> (struct x220fb_info *) kmalloc(sizeof(*p), GFP_ATOMIC);
Use:
struct fb_info *info = framebuffer_alloc(sizeof(struct private_par);
private_par = info->par;
> if(p==NULL)
> return -ENOMEM;
> memset(p, 0, sizeof(*p));
>
> init_waitqueue_head(&p->aclreq_wait);
> init_waitqueue_head(&p->setpar_wait);
> init_MUTEX(&p->setpar_sem);
> init_MUTEX(&p->ioctl_sem);
>
> info("Xilleon 220 Framebuffer Driver");
>
> /* set up a few more things, register framebuffer driver etc */
> p->gen.parsize = sizeof (struct x220fb_par);
> p->gen.fbhw = &x220fb_hwswitch;
>
> strcpy(p->gen.info.modename, "ATI ");
> strcat(p->gen.info.modename, x220fb_name);
> p->gen.info.changevar = NULL;
> p->gen.info.node = -1;
>
> p->gen.info.fbops = &x220fb_ops;
> p->gen.info.disp = &p->disp;
> p->gen.info.switch_con = &fbgen_switch;
> p->gen.info.updatevar = &fbgen_update_var;
> p->gen.info.blank = &fbgen_blank;
> p->gen.info.flags = FBINFO_FLAG_DEFAULT;
>
> calc_par(&p->curpar, &x220_default_var);
> var = &p->curpar.var;
>
> /* TODO: explain this crap */
> p->fb_addr_virt = (void *)__get_free_pages(GFP_KERNEL,
> p->curpar.fb_order);
> p->fb_addr_phys = virt_to_phys(p->fb_addr_virt);
> p->fake_offset = 1;
> info("Initial framebuffer at 0x%08x, mapped to %p, size %d",
> (u32)p->fb_addr_phys,
> p->fb_addr_virt,
> (int)p->curpar.fb_size);
>
> if (fbgen_do_set_var(&p->curpar.var, 1, &p->gen)) {
> err("boot video mode failed");
> goto ret_enxio;
> }
>
> p->disp.var = p->curpar.var;
> fbgen_set_disp(-1, &p->gen);
> fbgen_install_cmap(0, &p->gen);
>
> if (register_framebuffer(&p->gen.info) < 0) {
> goto ret_enxio;
> }
>
> if (!nodms)
> p->dms = 1;
>
> return 0;
>
> ret_enxio:
> kfree(p);
> iounmap(p->fb_addr_virt);
> return -ENXIO;
> }
>
>
> #ifdef MODULE
>
> static void __exit x220fb_exit(void)
> {
> unregister_framebuffer(&(fb_x220->gen.info));
> iounmap(fb_x220->fb_addr_virt);
> kfree(fb_x220);
> }
>
> module_init(x220fb_init);
> module_exit(x220fb_exit);
>
> MODULE_PARM(font, "s");
> MODULE_PARM_DESC(font, "Specifies a compiled-in font (default=none)");
> MODULE_PARM(accel, "i");
> MODULE_PARM_DESC(accel, "Enables hardware acceleration (default=0)");
> MODULE_PARM(nodms, "i");
> MODULE_PARM_DESC(nodms, "Disables dynamic mode selection (default=0)");
>
> #else
>
> int x220fb_setup(char *options)
> {
> char *this_opt;
>
> if (!options || !*options)
> return 1;
>
> for (this_opt = strtok(options, ","); this_opt;
> this_opt = strtok(NULL, ",")) {
> if (!strncmp(this_opt, "font:", 5)) {
> strcpy(fontname, this_opt+5);
> } else if (!strncmp(this_opt, "accel", 5)) {
> accel = 1;
> } else if (!strncmp(this_opt, "nodms", 3)) {
> nodms = 1;
> } else {
> mode_option = this_opt;
> }
> }
>
> return 0;
> }
>
> #endif /* MODULE */
>
>
> -------------------------------------------------------
> SF.Net email is Sponsored by the Better Software Conference & EXPO
> September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
> Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
> Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
> _______________________________________________
> Linux-fbdev-devel mailing list
> Linux-fbdev-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-fbdev-devel
>
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2005-09-12 10:00 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-11 12:03 porting a driver to the new fbdev api - part 2 Lior Balkohen
2005-09-12 9:59 ` Antonino A. Daplas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).