s3c2410fb.c
--> platform_driver
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe, //探针,在匹配到相应的设备资源模块的时候得到执行
.remove = s3c2410fb_remove, //移除,负责资源的释放等等
.suspend = s3c2410fb_suspend,//挂起
.resume = s3c2410fb_resume, //恢复,与挂起相对
.driver = { //名字匹配
.name = "s3c2410-lcd",
.owner = THIS_MODULE,
},
};
//此函数在加载模块的时候会被执行到
static int __init s3c2410fb_probe(struct platform_device *pdev)
--> struct s3c2410fb_info *info; //S3C2410的framebuffer信息
--> u32 pseudo_pal[16];
/* raw memory addresses */
dma_addr_t map_dma; /* physical */
u_char * map_cpu; /* virtual */
u_int map_size;
struct s3c2410fb_hw regs;
/* addresses of pieces placed in raw buffer */
u_char * screen_cpu; /* virtual address of buffer */
dma_addr_t screen_dma; /* physical address of buffer */
struct fb_info *fbinfo; //framebuffer结构体
struct s3c2410fb_hw *mregs; //S3C2410LCD控制器结构体
//mach_info里面有LCD的相关信息以及IO口定义
mach_info = pdev->dev.platform_data; //寻找核对S3C2410平台设备结构体有没有平台信息
if (mach_info == NULL) {
dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");
return -EINVAL;
}
mregs = &mach_info->regs; //得到LCD控制器寄存器信息
irq = platform_get_irq(pdev, 0); //里面是platform_get_resource(dev, IORESOURCE_IRQ, 0); 得到IRQ信息
fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); //分配一个fb_info结构体
strcpy(fbinfo->fix.id, driver_name); //拷贝驱动名信息 driver_name = “s3c2410fb”
/*设定fb_info的固定参数*/
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.type_aux = 0;
fbinfo->fix.xpanstep = 0;
fbinfo->fix.ypanstep = 0;
fbinfo->fix.ywrapstep = 0;
fbinfo->fix.accel = FB_ACCEL_NONE;
/*设定fb_info的可变参数*/
fbinfo->var.nonstd = 0;
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.height = mach_info->height;
fbinfo->var.width = mach_info->width;
fbinfo->var.accel_flags = 0;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->fbops = &s3c2410fb_ops;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &info->pseudo_pal; //调色板信息,调色板需要自己去构建
fbinfo->var.xres = mach_info->xres.defval;
fbinfo->var.xres_virtual = mach_info->xres.defval;
fbinfo->var.yres = mach_info->yres.defval;
fbinfo->var.yres_virtual = mach_info->yres.defval;
fbinfo->var.bits_per_pixel = mach_info->bpp.defval;
fbinfo->var.upper_margin = S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1;
fbinfo->var.lower_margin = S3C2410_LCDCON2_GET_VFPD(mregs->lcdcon2) + 1;
fbinfo->var.vsync_len = S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1;
fbinfo->var.left_margin = S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1;
fbinfo->var.right_margin = S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1;
fbinfo->var.hsync_len = S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1;
fbinfo->var.red.offset = 11;
fbinfo->var.green.offset = 5;
fbinfo->var.blue.offset = 0;
fbinfo->var.transp.offset = 0;
fbinfo->var.red.length = 5;
fbinfo->var.green.length = 6;
fbinfo->var.blue.length = 5;
fbinfo->var.transp.length = 0;
//整屏幕所需的空间,也就是framebuffer大小,单位字节
fbinfo->fix.smem_len = mach_info->xres.max *
mach_info->yres.max *
mach_info->bpp.max / 8;
/*清空调色板缓冲区,0x80000000*/
for (i = 0; i < 256; i++)
info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
info->clk = clk_get(NULL, "lcd"); //得到LCD控制器时钟频率
/* Initialize video memory */
ret = s3c2410fb_map_video_memory(info);
/*在内核里面分配一个屏幕framebuffer大小的空间*/
--> fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,&fbi->map_dma, GFP_KERNEL);
fbinfo->screen_base = fbi->map_cpu; //返回分配之后的虚拟地址
fbinfo->fix.smem_start = fbi->map_dma;//物理内存起始地址
ret = s3c2410fb_init_registers(info); //设置IO口,以及LCD控制器寄存器
--> modify_gpio(S3C2410_GPCUP, mach_info->gpcup, mach_info->gpcup_mask);
modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);
modify_gpio(S3C2410_GPDUP, mach_info->gpdup, mach_info->gpdup_mask);
modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);
writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);
writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);
writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);
writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);
ret = register_framebuffer(fbinfo); //注册fb_info结构体
//移除设备的时候调用到
static int s3c2410fb_remove(struct platform_device *pdev)
--> s3c2410fb_stop_lcd(info); //LCD使能寄存器位关闭
s3c2410fb_unmap_video_memory(info);
irq = platform_get_irq(pdev, 0);
free_irq(irq,info);
release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
unregister_framebuffer(fbinfo);
//定义平台设备驱动,与平台设备对应
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
.remove = s3c2410fb_remove,
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
.name = "s3c2410-lcd",
.owner = THIS_MODULE,
},
};
// S3C2410的资源,也就是LCD控制寄存器块
devs.c --> platform_device
static struct resource s3c_lcd_resource[] = {
[0] = {
.start = S3C24XX_PA_LCD,
.end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
//定义平台设备,与平台设备驱动对应
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
int unregister_framebuffer(struct fb_info *fb_info)
fb_mem.c:
类似于input.c一样的抽象层,应用程序读写设备的时候都会通过fb_mem.c来进行读写,fb_mem.c里面也会提供file_operations结构体进行读写函数的构建
最后由LCD液晶进行显示
如果在操作系统界面执行 echo hellow > /dev/tty1
若执行此命令的话会由tty1调用到我们设置的fb_info结构体,这个通过在register_framebuffer函数里面构建的registered_fb[]数组得到,然后
由tty1获取字符之后在framebuffer里面进行描述,然后LCD读取缓冲区里面的内容并显示到LCD屏幕上面
/*进行fb字符设备驱动的注册,并创建类,绑定file_operations结构体*/
static int __init fbmem_init(void)
{
create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
fb_class = class_create(THIS_MODULE, "graphics");
if (IS_ERR(fb_class)) {
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
fb_class = NULL;
}
return 0;
}
/*在lcd驱动里面进行fb_info的注册之后调用到此函数,然后在已经创建的类上面创建一个设备,设备名由fb设备的数量决定*/
int register_framebuffer(struct fb_info *fb_info)
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), "fb%d", i);
//之后执行上面的linux命令之后最后会有下面的file_operations结构体里面相应的处理函数进行相应的处理
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
};