一、LCD驱动程序框架分析
app: open("/dev/fb0", ...) 主设备号:29, 次设备号:0
————————————————————————————————————————————————————
kernel:(核心文件/drivers/video/fbmem.c)
fb_open
int fbidx = iminor(inode);
struct fb_info *info;
info = registered_fb[fbidx]; //根据次设备号获得从底层注册的struct fb_info结构体中
file->private_data = info;
if (info->fbops->fb_open) { //调用底层struct fb_info结构体中的fb_open函数
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
———————————————————————————————————————————————————
app: read()
_____________________________________________________________________________________
kernel:
fb_read
struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
if (info->fbops->fb_read)
return info->fbops->fb_read(info, buf, count, ppos);
src = (u32 __iomem *) (info->screen_base + p);
dst = buffer;
*dst++ = fb_readl(src++);
copy_to_user(buf, buffer, c)
怎么写LCD驱动程序?
1.分配一个fb_info结构体:framebuffer_alloc()
2.设置
3.注册:register_framebuffer
4.硬件相关的操作
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct lcd_regs {
unsigned long lcdcon1;
unsigned long lcdcon2;
unsigned long lcdcon3;
unsigned long lcdcon4;
unsigned long lcdcon5;
unsigned long lcdsaddr1;
unsigned long lcdsaddr2;
unsigned long lcdsaddr3;
unsigned long redlut;
unsigned long greenlut;
unsigned long bluelut;
unsigned long reserved[9];
unsigned long dithmode;
unsigned long tpal;
unsigned long lcdintpnd;
unsigned long lcdsrcpnd;
unsigned long lcdintmsk;
unsigned long lpcsel;
};
static struct fb_ops* s3c_lcdfb_ops = {
.owner = THIS_MODULE,
// .fb_setcplreg = atmel_lcdfb_setolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static struct fb_info* s3c_lcd;
static volatile unsigned long *gpbcon;
static volatile unsigned long *gpbdat;
static volatile unsigned long *gpccon;
static volatile unsigned long *gpdcon;
static volatile unsigned long *gpgcon;
static volatile struct lcd_regs* lcd_regs;
static u32 pseudo_palette[16]; //为了兼容,设置假的调色板
/* from pxafb.c */
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= 16 - bf->length;
return chan << bf->offset;
}
static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info)
{
unsigned int val;
if (regno > 16)
return 1;
/* 用red,green,blue三原色构造出val */
val = chan_to_field(red, &info->var.red);
val |= chan_to_field(green, &info->var.green);
val |= chan_to_field(blue, &info->var.blue);
//((u32 *)(info->pseudo_palette))[regno] = val;
pseudo_palette[regno] = val;
return 0;
}
static int lcd_init(void)
{
/* 1. 分配一个fb_info结构体 */
s3c_lcd = framebuffer_alloc(0, NULL);
/* 2. 设置 */
/* 2.1 设置固定的参数 */
strcpy(s3c_lcd->fix.id, "mylcd");
s3c_lcd->fix.smem_len = 320*240*32/8; /* MINI2440的LCD位宽是24,但是2440里会分配4字节即32位(浪费1字节) */
s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; /* 真彩色 */
s3c_lcd->fix.line_length = 320 * 4; /* 1行的字节数 */
/* 2.2 设置可变的参数 */
s3c_lcd->var.xres = 320;
s3c_lcd->var.yres = 240;
s3c_lcd->var.xres_virtual = 320;
s3c_lcd->var.yres_virtual = 240;
s3c_lcd->var.bits_per_pixel = 32; /* 每个像素所占的位数 */
/* RGB: 565 */
s3c_lcd->var.red.offset = 16;
s3c_lcd->var.red.length = 8;
s3c_lcd->var.green.offset = 8;
s3c_lcd->var.green.length = 8;
s3c_lcd->var.blue.offset = 0;
s3c_lcd->var.blue.length = 0;
s3c_lcd->var.activate = FB_ACTIVATE_NOW;
/* 2.3 设置操作函数 */
s3c_lcd->fops = &s3c_lcdfb_ops;
/* 2.4 其他设置 */
//s3c_lcd->pseudo_palette =; //
//s3c_lcd->screen_base = ; /* 显存的虚拟地址 */
s3c_lcd->screen_size = 320*240*32/8;
/* 3. 硬件相关的操作 */
/* 3.1 配置GPIO用于LCD */
gpbcon = ioremap(0x56000010, 8);
gpbdat = gpbcon+1;
gpccon = ioremap(0x56000020, 4);
gpdcon = ioremap(0x56000030, 4);
gpgcon = ioremap(0x56000060, 4);
*gpccon = 0xaaaaaaaa; /* GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */
*gpdcon = 0xaaaaaaaa; /* GPIO管脚用于VD[23:8] */
// *gpbcon &= ~(3); /* GPB0设置为输出引脚 */
// *gpbcon |= 1;
// *gpbdat &= ~1; /* 输出低电平 */
*gpgcon |= (3<<8); /* GPG4用作LCD_PWREN */
/* 3.2 根据LCD手册设置LCD控制器,比如VCLK的频率等 */
lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
/*
* MINI2440 LCD 3.5英寸 ZQ3506_V0 SPEC.pdf 第11、12页
*
* LCD手册11,12页和2440手册"Figure 15-6. TFT L
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』