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 };