概述
首先定义了一个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, ¶m);
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队列的分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复