我是靠谱客的博主 无限服饰,最近开发中收集的这篇文章主要介绍有关mtkfb中screen_update队列的分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

首先定义了一个task

static struct task_struct *screen_update_task = NULL;

在probe中进行了初始化:

    init_waitqueue_head(&screen_update_wq);
    screen_update_task = kthread_create( screen_update_kthread, NULL, "screen_update_kthread");

    if (IS_ERR(screen_update_task)) {
        return PTR_ERR(screen_update_task);
    }
    wake_up_process(screen_update_task);

上面的代码已经完成这个task的创建,并通过wake_up_process将该kthread给运行起来了,在adb shell 下 ps也是可以看到一个screen_update_kthread的进程的。

线程中的函数

static int screen_update_kthread(void *data)
{
struct sched_param param = { .sched_priority = RTPM_PRIO_SCRN_UPDATE };
sched_setscheduler(current, SCHED_RR, &param);   
    for( ;; ) {
        wait_event_interruptible(screen_update_wq, atomic_read(&has_pending_update));
        mtkfb_update_screen_impl();
atomic_set(&has_pending_update,0);
        if (kthread_should_stop())
            break;
    }
    return 0;
}

这个函数开始就通过sched_setschedulers来设置进行的调度,修改优先级,SCHED_RR表示居于时间片的调度,当时间片用完,会将该进程放到就绪队列中等待cpu的调度。

for循环中通过wait_event_interruptible函数设置screen_update_wq进入可中断的休眠。

加入kthread_should_stop()函数的原因是要在开启线程的函数中加入该函数,否则kthread_stop是不会起作用的。

mtkfb_update_screen_impl()函数会调用DISP_CHECK_RET(DISP_UpdateScreen(0, 0, fb_xres_update, fb_yres_update));来更新屏幕。


之后需要分析的是screen_update_wq这个wait_queue_head_t.

有关这个结构体相关的说明可在这个博客中看到:http://www.cnblogs.com/noaming1900/archive/2011/01/14/1935526.html

screen_update_wq其实就是一个等待队列头,

init_waitqueue_head(&screen_update_wq);进行了初始化,

之后在

static void mtkfb_lcd_complete_interrupt(void *param)
{
printk("%sn",__func__);
if(atomic_read(&has_pending_update))
    {
        wake_up_interruptible(&screen_update_wq);
    }

}

这个queue的唤醒和休眠以来has_pending_update这个变量,这个变量在初始化时是为0,

在static int mtkfb_update_screen(struct fb_info *info)

{

........................

if(DISP_IsInOverlayMode())
{
if(DISP_IsLCDBusy())
{
atomic_set(&has_pending_update,1);
goto End;
}

..........................

}

和上面的screen_update_kthread 两个函数中会被重新设值。


整体的流程大概是这样的:screen_update_task这个进程启动之后会一直会调用wait_event_interruptible(screen_update_wq, atomic_read(&has_pending_update));函数将

screen_update_wq这个等待队列置为休眠,如果has_pending_update为1,则会唤醒等待队列,并将had_pending_update设置为0.而在mtkfb_lcd_complete_interrupt函数中,如果had_pending_update为1,则wake_up_intertuptible函数将该等待队列唤醒。而关键的had_pending_update变量,一直都是0的,除非DISP_IsLCDBusy()发生。

screen_update_task中的for循环会一直调用wait_event_interruptible函数来休眠screen_update_wq,而mtkfb_lcd_complete_interrupt函数正好相反,这个函数在什么什么时候调用的呢?

    {
        ///register LCD complete interrupt callback
        DISP_INTERRUPT_CALLBACK_STRUCT cbStruct;
        cbStruct.pFunc = mtkfb_lcd_complete_interrupt;
        cbStruct.pParam = NULL;
        /// regster callback
        if (DISP_STATUS_OK != DISP_SetInterruptCallback(DISP_LCD_TRANSFER_COMPLETE_INT, &cbStruct))
        {
            ASSERT(0);
        }
    }

再进到DISP_SetInterruptCallback去,

        offset = eventID - DISP_LCD_INTERRUPT_EVENTS_START;
        DISP_CallbackArray[offset].pFunc = pCBStruct->pFunc;
        DISP_CallbackArray[offset].pParam = pCBStruct->pParam;
        
        LCD_CHECK_RET(LCD_SetInterruptCallback(_DISP_InterruptCallbackProxy));
        LCD_CHECK_RET(LCD_EnableInterrupt(eventID));

再进到LCD_SetInterruptCallback中去:

LCD_STATUS LCD_SetInterruptCallback(void (*pCB)(DISP_INTERRUPT_EVENTS))
{
    _lcdContext.pIntCallback = pCB;
    return LCD_STATUS_OK;
}

再有一个函数比较关键:

#if ENABLE_LCD_INTERRUPT
static irqreturn_t _LCD_InterruptHandler(int irq, void *dev_id)
{   
    LCD_REG_INTERRUPT status = LCD_REG->INT_STATUS;
    if (status.COMPLETED)
    {
#ifdef CONFIG_MTPROF_APPLAUNCH  // eng enable, user disable  
#endif
        wake_up_interruptible(&_lcd_wait_queue);
        if(_lcdContext.pIntCallback)
            _lcdContext.pIntCallback(DISP_LCD_TRANSFER_COMPLETE_INT);
        DBG_OnLcdDone();
    }

.................

这里就应该比较清晰了,

request_irq(MT6577_LCD_IRQ_ID,
        _LCD_InterruptHandler, IRQF_TRIGGER_LOW, "mtklcd", NULL)

这个中断大概是每次刷屏的时候会产生,之后在_LCD_InterruptHandle中会调用 _lcdContext.pIntCallback函数,也就是:_DISP_InterruptCallbackProxy这个函数,这个函数中会根据事件的类型,调用到 DISP_CallbackArray[offset].pFunc(DISP_CallbackArray[offset].pParam);也就是最开始定义的mtkfb_lcd_complete_interrupt函数。

简单的说,每次刷屏完会有一个中断产生,调到_LCD_InterruptHandle这个函数,顺便提一个这个函数中DBG_OnLcdDone();这个是调试lcd的帧率的,可以调试输出每一帧传输的时间已经TE花费的时间。中断函数最终调到mtkfb_lcd_complete_interrupt这里,这里会判断has_pending_update这个值,将screen_update_wq这个等待工作队列唤醒。而has_pending_update这个变量只有在DISP_IsLCDBusy的时候才会被设置为1.

理论上来说,不管screen_update_wq这个跑不跑,screen_update_kthread里面的for循环是一直执行下去的,但我加的log却从没有打印出来,mtkfb_update_screen_impl的调用是通过ioctl调用下来的。

写个笔记从早上写道晚上,中间还不时有人来扰,吃完晚上还打了个小时羽毛球,得抓紧效率啊。






 

最后

以上就是无限服饰为你收集整理的有关mtkfb中screen_update队列的分析的全部内容,希望文章能够帮你解决有关mtkfb中screen_update队列的分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(61)

评论列表共有 0 条评论

立即
投稿
返回
顶部