linux中LCD设备驱动(3)——基于s3c6410平台

s3c6410硬件DISPLAY CONTROLLER(显示控制器)的地址链接

linux中LCD设备驱动(1)——framebuffer(帧缓冲)的链接地址

linux中LCD设备驱动(2)——基于s3c6410平台的链接地址


上一篇在说LCD设备驱动对应的probe函数时,没有说完,这一篇接着继续说probe函数。


s3cfb_pre_init();上一次说到了这个函数,而且还讲到了一个结构体s3cfb_fimd_info_t,并说了它的大致作用。
s3cfb_set_backlight_power(1);看名字就只到它的大致作用,与背光灯有关,源码如下:

static void s3cfb_set_backlight_power(int to)
{
s3cfb_fimd.backlight_power = to;


if (s3cfb_fimd.set_backlight_power)
(s3cfb_fimd.set_backlight_power)(to);  函数指针
}

s3cfb_set_lcd_power(1);和上的类似,列出其源码:

static void s3cfb_set_lcd_power(int to)
{
s3cfb_fimd.lcd_power = to;


if (s3cfb_fimd.set_lcd_power)
(s3cfb_fimd.set_lcd_power)(to);也是函数指针
}

s3cfb_set_backlight_level(S3CFB_DEFAULT_BACKLIGHT_LEVEL);也和上面差不多,就不说了。


info->clk = clk_get(NULL, "lcd");得到LCD对应的时钟

if (!info->clk || IS_ERR(info->clk)) {
printk(KERN_INFO "failed to get lcd clock source\n");
ret =  -ENOENT;
goto release_io;
}

clk_enable(info->clk);  使能时钟
printk("S3C_LCD clock got enabled :: %ld.%03ld Mhz\n", PRINT_MHZ(clk_get_rate(info->clk)));


s3cfb_fimd.vsync_info.count = 0;
init_waitqueue_head(&s3cfb_fimd.vsync_info.wait_queue);   //初始化帧同步信号的等待队列头


res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);获取LCD平台设备所使用的中断号

if (res == NULL) {
dev_err(&pdev->dev, "failed to get irq\n");
ret = -ENXIO;
goto release_clock;
}


ret = request_irq(res->start, s3cfb_irq, 0, "s3c-lcd", pdev);  //申请中断,中断处理函数为s3cfb_irq

if (ret != 0) {
printk("Failed to install irq (%d)\n", ret);
goto release_clock;
}


msleep(5);


for (index = 0; index < S3CFB_NUM; index++) {    这一点不是很理解,不明白S3CFB_NUM的含义?查看了2410的代码,发现没有这个循环。我猜测与6410的多层窗口显示有关。我在s3c6410的硬件LCD显示控制器那篇博客中,有过这么一句话:“显示控制器支持5 层图像窗口。”所以我才做这样的猜测。如果你知道了话,请告诉我,谢谢!

#define S3CFB_NUMFB_MIN_NUM(S3CFB_MAX_NUM, CONFIG_FB_S3C_NUM)
#define FB_MIN_NUM(x, y)((x) < (y) ? (x) : (y))  其实就是x,y中的最小值,也就是S3CFB_MAX_NUM和CONFIG_FB_S3C_NUM中的最小值。又有如下定义:
#elif defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) || defined(CONFIG_CPU_S5PC100)
#define S3CFB_MAX_NUM 5
#define CONFIG_FB_S3C_NUM   4

s3cfb_info[index].mem = info->mem;
s3cfb_info[index].io = info->io;
s3cfb_info[index].clk = info->clk;


s3cfb_init_fbinfo(&s3cfb_info[index], driver_name, index);

填充fb_info中的可变参数结构的成员和不可变参数结构的成员,fb_info结构体中个成员的含义我在第一篇中说过了,你可以去查看。源码如下:

static void s3cfb_init_fbinfo(s3cfb_info_t *finfo, char *drv_name, int index)
{
int i = 0;


if (index == 0)
s3cfb_init_hw();


strcpy(finfo->fb.fix.id, drv_name);


finfo->win_id = index;
finfo->fb.fix.type = FB_TYPE_PACKED_PIXELS;
finfo->fb.fix.type_aux = 0;
finfo->fb.fix.xpanstep = 0;
finfo->fb.fix.ypanstep = 1;
finfo->fb.fix.ywrapstep = 0;
finfo->fb.fix.accel = FB_ACCEL_NONE;


finfo->fb.fbops = &s3cfb_ops;
finfo->fb.flags= FBINFO_FLAG_DEFAULT;


finfo->fb.pseudo_palette = &finfo->pseudo_pal;


finfo->fb.var.nonstd = 0;
finfo->fb.var.activate = FB_ACTIVATE_NOW;
finfo->fb.var.accel_flags = 0;
finfo->fb.var.vmode = FB_VMODE_NONINTERLACED;


finfo->fb.var.xoffset = s3cfb_fimd.xoffset;
finfo->fb.var.yoffset = s3cfb_fimd.yoffset;


if (index == 0) {
finfo->fb.var.height = s3cfb_fimd.height;
finfo->fb.var.width = s3cfb_fimd.width;


finfo->fb.var.xres = s3cfb_fimd.xres;
finfo->fb.var.yres = s3cfb_fimd.yres;


finfo->fb.var.xres_virtual = s3cfb_fimd.xres_virtual;
finfo->fb.var.yres_virtual = s3cfb_fimd.yres_virtual;
} else {
finfo->fb.var.height = s3cfb_fimd.osd_height;
finfo->fb.var.width = s3cfb_fimd.osd_width;


finfo->fb.var.xres = s3cfb_fimd.osd_xres;
finfo->fb.var.yres = s3cfb_fimd.osd_yres;


finfo->fb.var.xres_virtual = s3cfb_fimd.osd_xres_virtual;
finfo->fb.var.yres_virtual = s3cfb_fimd.osd_yres_virtual;
}


finfo->fb.var.bits_per_pixel = s3cfb_fimd.bpp;
        finfo->fb.var.pixclock = s3cfb_fimd.pixclock;
finfo->fb.var.hsync_len = s3cfb_fimd.hsync_len;
finfo->fb.var.left_margin = s3cfb_fimd.left_margin;
finfo->fb.var.right_margin = s3cfb_fimd.right_margin;
finfo->fb.var.vsync_len = s3cfb_fimd.vsync_len;
finfo->fb.var.upper_margin = s3cfb_fimd.upper_margin;
finfo->fb.var.lower_margin = s3cfb_fimd.lower_margin;
finfo->fb.var.sync = s3cfb_fimd.sync;
finfo->fb.var.grayscale = s3cfb_fimd.cmap_grayscale;


finfo->fb.fix.smem_len = finfo->fb.var.xres_virtual * finfo->fb.var.yres_virtual * s3cfb_fimd.bytes_per_pixel;
finfo->fb.fix.line_length = finfo->fb.var.width * s3cfb_fimd.bytes_per_pixel;


#if !defined(CONFIG_FB_S3C_VIRTUAL_SCREEN)


#if defined(CONFIG_FB_S3C_DOUBLE_BUFFERING)
if (index < 2)
finfo->fb.fix.smem_len *= 2;
#else
/*
* Some systems(ex. DirectFB) use FB0 memory as a video memory.
* You can modify the size of multiple.
*/
if (index == 0)
finfo->fb.fix.smem_len *= 5;
#endif


#endif

for (i = 0; i < 256; i++)
finfo->palette_buffer[i] = S3CFB_PALETTE_BUFF_CLEAR;
}



/* Initialize video memory */  帧缓冲设备显示缓冲区的内存分配
ret = s3cfb_map_video_memory(&s3cfb_info[index]);

if (ret) {
printk("Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto release_irq;
}


ret = s3cfb_init_registers(&s3cfb_info[index]);  对LCD各寄存器进行初始化,列出部分源码:

int s3cfb_init_registers(s3cfb_info_t *fbi)
{

               ..........

                writel(s3cfb_fimd.wincon0, S3C_WINCON0);
writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);
writel(s3cfb_fimd.vidcon1, S3C_VIDCON1);
writel(s3cfb_fimd.vidtcon0, S3C_VIDTCON0);
writel(s3cfb_fimd.vidtcon1, S3C_VIDTCON1);
writel(s3cfb_fimd.vidtcon2, S3C_VIDTCON2);
writel(s3cfb_fimd.dithmode, S3C_DITHMODE);

              ...........

}
ret = s3cfb_check_var(&s3cfb_info[index].fb.var, &s3cfb_info[index].fb);此函数检查fb的相关参数,如果传递的参数不合法,则进行修改。列出其函数开头的注释:

/*
 * s3cfb_check_var():
 * Get the video params out of 'var'. If a value doesn't fit, round it up,
 * if it's too big, return -EINVAL.
 *
 */


if (index < 2){
if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0) < 0)这个函数和调色板有关,同样列出其注释:

/**
 * fb_alloc_cmap - allocate a colormap
 * @cmap: frame buffer colormap structure
 * @len: length of @cmap
 * @transp: boolean, 1 if there is transparency, 0 otherwise
 *
 * Allocates memory for a colormap @cmap.  @len is the
 * number of entries in the palette.
 *
 * Returns negative errno on error, or zero on success.
 *
 */

goto dealloc_fb;
} else {
if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 16, 0) < 0)
goto dealloc_fb;
}


ret = register_framebuffer(&s3cfb_info[index].fb); 注册这个帧缓冲设备(FrameBuffer)fb_info到系统当中,函数源码如下:这个函数的主要作用其实就是把fb_info结构体加入到全局量struct fb_info *registered_fb[FB_MAX]数组中,还有进行一些其他的初始化。

/**
 *register_framebuffer - registers a frame buffer device
 *@fb_info: frame buffer info structure
 *
 *Registers a frame buffer device @fb_info.
 *
 *Returns negative errno on error, or zero for success.
 *
 */


int
register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
s


if (num_registered_fb == FB_MAX)
return -ENXIO;


if (fb_check_foreignness(fb_info))
return -ENOSYS;


num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
fb_info->node = i;
mutex_init(&fb_info->lock);


fb_info->dev = device_create(fb_class, fb_info->device,
     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
if (IS_ERR(fb_info->dev)) {
/* Not fatal */
printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
fb_info->dev = NULL;
} else
fb_init_device(fb_info);


if (fb_info->pixmap.addr == NULL) {
fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->pixmap.addr) {
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = 1;
fb_info->pixmap.scan_align = 1;
fb_info->pixmap.access_align = 32;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = 0;


if (!fb_info->pixmap.blit_x)
fb_info->pixmap.blit_x = ~(u32)0;


if (!fb_info->pixmap.blit_y)
fb_info->pixmap.blit_y = ~(u32)0;


if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist);


fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info;


event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
return 0;
}




if (ret < 0) {
printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);
goto free_video_memory;
}


printk(KERN_INFO "fb%d: %s frame buffer device\n", s3cfb_info[index].fb.node, s3cfb_info[index].fb.fix.id);
}


/* create device files */下面这些代码是对设备文件系统的支持,创建fb设备文件。
ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);


if (ret < 0)
printk(KERN_WARNING "s3cfb: failed to add entries\n");


ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);


if (ret < 0)
printk(KERN_WARNING "s3cfb: failed to add entries\n");


ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);


if (ret < 0)
printk(KERN_WARNING "s3cfb: failed to add entries\n");


return 0;

下面这些是错误处理函数:

free_video_memory:    
s3cfb_unmap_video_memory(&s3cfb_info[index]);


release_irq:
free_irq(res->start, &info);


release_clock:
clk_disable(info->clk);
clk_put(info->clk);


release_io:
iounmap(info->io);


release_mem:
release_resource(info->mem);
kfree(info->mem);


dealloc_fb:
framebuffer_release(fbinfo);
return ret;
}

probe函数最主要的工作,就是对fb设备进行一定的初始化,申请内存等等,然后注册fb_info到系统中。

2、对应的romeve函数就不说了,就是对应申请的资源的释放,和注销fb_info结构体。


linux中LCD设备驱动(4)——基于s3c6410平台的链接地址



你可能感兴趣的:(c,linux,video,buffer,平台,structure)