linux驱动之--lcd

其实fb核心层代码包括如下:
fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o fbcvt.o

fbmem.c的分析

subsys_initcall(fbmem_init);

static int __init fbmem_init(void)
|
proc_create(“fb”, 0, NULL, &fb_proc_fops);
//注册字符设备,主设备号为29
register_chrdev(FB_MAJOR,”fb”,&fb_fops);
//创建/sys/class/graphics
fb_class = class_create(THIS_MODULE, “graphics”);


s3c-fb.c层

module_init(s3c_fb_init);
module_exit(s3c_fb_cleanup);

//平台设备资源以及私有数据mach-smdkv210.c和dev-fb.c中
static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
.win[0] = &smdkv210_fb_win0,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = s5pv210_fb_gpio_setup_24bpp,
};
struct platform_device s3c_device_fb = {
.name = “s3c-fb”,
.id = -1,
.num_resources = ARRAY_SIZE(s3c_fb_resource),
.resource = s3c_fb_resource,
.dev.dma_mask = &s3c_device_fb.dev.coherent_dma_mask,
.dev.coherent_dma_mask = 0xffffffffUL,
};
// s3c-fb.c文件中就有这个
static struct platform_device_id s3c_fb_driver_ids[] = {
{
.name = “s3c-fb”,
.driver_data = (unsigned long)&s3c_fb_data_64xx,
}, {
.name = “s5pc100-fb”,
.driver_data = (unsigned long)&s3c_fb_data_s5pc100,
}, {
.name = “s5pv210-fb”,
.driver_data = (unsigned long)&s3c_fb_data_s5pv210,
}, {
.name = “s3c2443-fb”,
.driver_data = (unsigned long)&s3c_fb_data_s3c2443,
},
{},
};

static struct platform_driver s3c_fb_driver = {
.probe = s3c_fb_probe,————————————
.remove = __devexit_p(s3c_fb_remove), |
.id_table = s3c_fb_driver_ids, |
.driver = { |
.name = “s3c-fb”, |
.owner = THIS_MODULE, |
.pm = &s3cfb_pm_ops, |
}, |
}; |
|
s3c_fb_init(void) |
| |
platform_driver_register(&s3c_fb_driver); |
|
|
s3c_fb_probe(struct platform_device *pdev)<——————————–
|
struct s3c_fb_driverdata *fbdrv;
const struct platform_device_id *platid;

//从平台设备数据中获取设备idtable,这个比较有意思
//在总线match的时候,如果match成功,pdev->id_entry = id(pdrv中的);
platid = platform_get_device_id(pdev);  
//这里面涉及到类型转换,比较奇特,driver_data是一个整数,实际是一个可以记录地址的变量
//实际就是前面的s3c_fb_data_64xx
fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;

// 获取平台数据
pd = pdev->dev.platform_data;

//分配驱动特定数据对象
sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);

// 初始化特定数据对象, 记录基本device对象,平台数据,
sfb->dev = dev;
sfb->pdata = pd;
// fb驱动的的可变数据
sfb->variant = fbdrv->variant;

// 使能时钟
sfb->bus_clk = clk_get(dev, "lcd");
clk_enable(sfb->bus_clk);

//获取平台设备资源:控制寄存器地址和中断
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sfb->regs_res = request_mem_region(res->start, resource_size(res),dev_name(dev));
sfb->regs = ioremap(res->start, resource_size(res));

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
sfb->irq_no = res->start;
//申请中断,出发条件为NONE
ret = request_irq(sfb->irq_no, s3c_fb_irq,0, "s3c_fb", sfb);
//保存特定数据对象,供remove使用
platform_set_drvdata(pdev, sfb);

//利用平台设备私有数据中的gpio函数,设置gpio功能,比如VSYN,HSYN等引脚
pd->setup_gpio();

//设置VIDCON1
writel(pd->vidcon1, sfb->regs + VIDCON1);
// 将5个窗口的配置寄存器全部复位VIDOSD_A/B/C
for (win = 0; win < fbdrv->variant.nr_windows; win++)
    s3c_fb_clear_win(sfb, win);

//初始化所有窗口的颜色控制寄存器
writel(0xffffff, regs + WKEYCON0);
writel(0xffffff, regs + WKEYCON1);

// probe所有的窗口
for (win = 0; win < fbdrv->variant.nr_windows; win++)
    //只有平台设备私有数据pd->win[win]不为空才能执行s3c_fb_probe_win
    if (!pd->win[win])
        continue;
    s3c_fb_probe_win(sfb, win, fbdrv->win[win],&sfb->windows[win]);----------------
                                            |

———————————————————- |
s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,<————————————–|
struct s3c_fb_win_variant *variant,
struct s3c_fb_win **res)
|
// 可变参数
struct fb_var_screeninfo *var;
// 窗口对象指针
struct s3c_fb_win *win;
// 记录了帧缓冲设备的全部信息对象
struct fb_info *fbinfo;
//初始化等待队列
init_waitqueue_head(&sfb->vsync_info.wait);

//设置调色板
palette_size = variant->palette_sz * 4;

//分配一个fbinfo,一个窗口win对应一个fbinfo
fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
               palette_size * sizeof(u32), sfb->dev);


//win通过res参数返回给调用者,实际这个写在后面就容易理解一点
*res = win;
//win会保存到fbinfo->par,这个写在后面也容易理解点
win = fbinfo->par;
//var指向fbinfo->var,只要初始化了var,就初始化了fbinfo->var
var = &fbinfo->var;

//初始化struct s3c_fb_win对象,必须还要记得,本代码是在一个循环里面的
win->variant = *variant;
win->fbinfo = fbinfo;
win->parent = sfb;
win->windata = windata;
win->index = win_no;
win->palette_buffer = (u32 *)(win + 1);

//通过dma为window分配一个内存空间,内存地址会被记录在struct fb_info中的screen_base
s3c_fb_alloc_memory(sfb, win);
        |
        fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,&map_dma, GFP_KERNEL);
        //固定参数也记录framebuffer的物理内存地址
        fbi->fix.smem_start = map_dma;
//设置fb的可变参数,可变参数的值都来自于initmode = &windata->win_mode;
//windata = sfb->pdata->win[win_no];
//也即是来自于平台设备数据中的smdkv210_fb_win0,主要有前肩,后肩等数据
fb_videomode_to_var(&fbinfo->var, initmode);

//设置fbinfo的文件操作对象
fbinfo->fbops       = &s3c_fb_ops;
//设置各个引脚的时序,像素位宽,将分配好的dma内存起始和结束地址保存到相应寄存器中
s3c_fb_set_par(fbinfo);
    |
    writel(info->fix.smem_start, buf + sfb->variant.buf_start);
//注册分配好的fbinfo
register_framebuffer(fbinfo);
    |
    //实际就是将fbinfo加入到一个数组中:registered_fb[FB_MAX];并为其注册为一个设备
    //创建相应的设备文件/dev/fb0,fb1...
    do_register_framebuffer(fb_info);
        |
        struct fb_event event;
        //计数
        num_registered_fb++;
        //找一个没有使用的位置
        for (i = 0 ; i < FB_MAX; i++)
            if (!registered_fb[i])
                break;
        //记录编号
        fb_info->node = i;
        //创建文件
        fb_info->dev = device_create(fb_class, fb_info->device,
                 MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
        //保存到全局的数组中
        registered_fb[i] = fb_info;
        event.info = fb_info;

===================================================================================================
应用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值