[ZLG-ARM] 这些**很经典

[复制链接]
2082|2
 楼主| ddpxy 发表于 2009-4-2 12:05 | 显示全部楼层 |阅读模式
三、解剖s3c2410fb_driver变量<br />s3c2410fb_driver变量有什么作用呢?在前面的2.2节提到了它的定义,从它的原型可以看出s3c2410fb_driver是个platform_driver类型的变量,前面的几个小节提到了从platform_driver的名字可以看出它应该是platform_device的驱动类型。为了方便阅读,这里再贴一次s3c2410fb_driver的定义:<br />static&nbsp;struct&nbsp;platform_driver&nbsp;s3c2410fb_driver&nbsp;=&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.probe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;s3c2410fb_probe,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.remove&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;s3c2410fb_remove,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.suspend&nbsp;&nbsp;=&nbsp;s3c2410fb_suspend,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.resume&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;s3c2410fb_resume,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.driver&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&quot;s3c2410-lcd&quot;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.owner&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;THIS_MODULE,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />};<br />从定义可以看出,该platform_device的驱动函数有s3c2410fb_probe,s3c2410fb_remove,s3c2410fb_suspend和s3c2410fb_suspend。.resource成员前面的章节有说明,.driver成员的值相信不用再说明了吧,再明白不过了。前面的章节,s3c2410fb_probe被比较详细的介绍,这节中的主要任务就是解释其他的几个函数。在解释他们之前,s3c2410fb_probe里面在该函数结尾的时候调用了几个函数没有说到,所以在这里补上。<br /><br />3.1&nbsp;s3c2410fb_probe<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在s3c2410fb_probe中最好调用了s3c2410fb_init_registers和s3c2410fb_check_var函数,这里应该将他们交代清楚。很显然,s3c2410fb_init_registers是初始化相关寄存器。那么后者呢?这里先把s3c2410fb_init_registers搞定再说。s3c2410fb_init_registers的定义与实现如下,先根据它的指向流程,一步一步解释:<br /><br />static&nbsp;int&nbsp;s3c2410fb_init_registers(struct&nbsp;s3c2410fb_info&nbsp;*fbi)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;flags;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Initialise&nbsp;LCD&nbsp;with&nbsp;values&nbsp;from&nbsp;haret&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local_irq_save(flags);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;关闭中断,在关闭中断前,中断的当前状态被保存在flags中,对于关闭中断的函数,linux内核有很多种,可以查阅相关的资料。*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;modify&nbsp;the&nbsp;gpio(s)&nbsp;with&nbsp;interrupts&nbsp;set&nbsp;(bjd)&nbsp;*/<br />/*下面的modify_gpio函数是修改处理器GPIO的工作模式,它的实现很简单,将第二个参数的值与第三个参数的反码按位与操作后,在写到第一个参数。这里的第一个参数实际就是硬件的GPIO控制器。*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modify_gpio(S3C2410_GPCUP,&nbsp;&nbsp;mach_info-&gtgpcup,&nbsp;&nbsp;mach_info-&gtgpcup_mask);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modify_gpio(S3C2410_GPCCON,&nbsp;mach_info-&gtgpccon,&nbsp;mach_info-&gtgpccon_mask);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modify_gpio(S3C2410_GPDUP,&nbsp;&nbsp;mach_info-&gtgpdup,&nbsp;&nbsp;mach_info-&gtgpdup_mask);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modify_gpio(S3C2410_GPDCON,&nbsp;mach_info-&gtgpdcon,&nbsp;mach_info-&gtgpdcon_mask);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local_irq_restore(flags);&nbsp;&nbsp;//使能中断,并恢复以前的状态<br />&nbsp;&nbsp;/*下面的几个writel函数开始初始化LCD控制寄存器,它的值就是我们在smdk2410_lcd_platdata(arch/arm/mach-s3c2410/mach-smdk2410.c)中regs域的值。*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writel(fbi-&gtregs.lcdcon1,&nbsp;S3C2410_LCDCON1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writel(fbi-&gtregs.lcdcon2,&nbsp;S3C2410_LCDCON2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writel(fbi-&gtregs.lcdcon3,&nbsp;S3C2410_LCDCON3);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writel(fbi-&gtregs.lcdcon4,&nbsp;S3C2410_LCDCON4);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writel(fbi-&gtregs.lcdcon5,&nbsp;S3C2410_LCDCON5);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s3c2410fb_set_lcdaddr(fbi);&nbsp;&nbsp;&nbsp;&nbsp;/*该函数的主要作用是让处理器的LCD控制器的三个地址寄存器指向正确的位置,这个位置就是LCD的缓冲区,详细的情况可以参见s3c2410的用户手册。*/<br />……<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Enable&nbsp;video&nbsp;by&nbsp;setting&nbsp;the&nbsp;ENVID&nbsp;bit&nbsp;to&nbsp;1&nbsp;这里打开video,在s3c2410fb_probe中被关闭了,这里打开*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fbi-&gtregs.lcdcon1&nbsp;|=&nbsp;S3C2410_LCDCON1_ENVID;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writel(fbi-&gtregs.lcdcon1,&nbsp;S3C2410_LCDCON1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />}<br />OK,s3c2410fb_init_registers就简单介绍到这里。下面看看s3c2410fb_check_var函数要干些什么事,要说到这个函数,还得提到fb_var_screeninfo结构类型,与它对应的是fb_fix_screeninfo结构类型。这两个类型分别代表了显示屏的属性信息,这些信息可以分为可变属性信息(如:颜色深度,分辨率等)和不可变的信息(如帧缓冲的其实地址)。既然fb_var_screeninfo表示了可变的属下信息,那么这些可变信息就应该有一定范围,否则显示就会出问题,所以s3c2410fb_check_var函数的功能就是要在LCD的帧缓冲驱动开始运行之前将这些值初始到合法的范围内。知道了s3c2410fb_check_var要做什么,再去阅读s3c2410fb_check_var函数的代码就没什么问题了。<br /><br />3.2&nbsp;s3c2410fb_remove<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从这里开始将解释s3c2410fb_driver中的其他几个函数。那么就从s3c2410fb_remove开刀吧!顾名思义该函数就该知道,它要将这个platform设备从系统中移除,可以推测它应该释放掉所有的资源,包括内存空间,中断线等等。还是按照惯例,在它的实现代码中一步步的解释。<br />static&nbsp;int&nbsp;s3c2410fb_remove(struct&nbsp;platform_device&nbsp;*pdev)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;fb_info&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*fbinfo&nbsp;=&nbsp;platform_get_drvdata(pdev);&nbsp;&nbsp;/*该函数从platform_device中,到fb_info信息*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;s3c2410fb_info&nbsp;*info&nbsp;=&nbsp;fbinfo-&gtpar;&nbsp;&nbsp;//得到私有数据<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;irq;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s3c2410fb_stop_lcd(info);&nbsp;&nbsp;&nbsp;&nbsp;//该函数停止LCD控制器,实现可以在s3c2410fb.c中找到<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msleep(1);&nbsp;//休息以下,等待LCD停止<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s3c2410fb_unmap_video_memory(info);&nbsp;&nbsp;&nbsp;//该函数释放缓冲区<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(info-&gtclk)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//停止时钟<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clk_disable(info-&gtclk);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clk_put(info-&gtclk);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info-&gtclk&nbsp;=&nbsp;NULL;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irq&nbsp;=&nbsp;platform_get_irq(pdev,&nbsp;0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//得到中断线,以便释放<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free_irq(irq,info);&nbsp;&nbsp;&nbsp;&nbsp;//释放该中断<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;release_mem_region((unsigned&nbsp;long)S3C24XX_VA_LCD,&nbsp;S3C24XX_SZ_LCD);&nbsp;/*&nbsp;释放内存空间&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unregister_framebuffer(fbinfo);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//向内核注销该帧缓冲<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />}<br /><br />3.3&nbsp;s3c2410fb_suspend与s3c2410fb_resume<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在实际的设备,常常可以看到LCD在不需要的时候进入休眠状态,当需要使用的时候又开始工作,比如手机,在不需要的时候LCD就熄灭,当需要使用的时候LCD又被点亮。从实际中可以看出这对函数非常重要。虽然他们很重要,但不一定很复杂,下面看看它们是怎么样实现的。<br /><br />static&nbsp;int&nbsp;s3c2410fb_suspend(struct&nbsp;platform_device&nbsp;*dev,&nbsp;pm_message_t&nbsp;state)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;fb_info&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*fbinfo&nbsp;=&nbsp;platform_get_drvdata(dev);&nbsp;&nbsp;//这两条语句好面熟^_^<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;s3c2410fb_info&nbsp;*info&nbsp;=&nbsp;fbinfo-&gtpar;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s3c2410fb_stop_lcd(info);&nbsp;&nbsp;//停止LCD<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;sleep&nbsp;before&nbsp;disabling&nbsp;the&nbsp;clock,&nbsp;we&nbsp;need&nbsp;to&nbsp;ensure<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;the&nbsp;LCD&nbsp;DMA&nbsp;engine&nbsp;is&nbsp;not&nbsp;going&nbsp;to&nbsp;get&nbsp;back&nbsp;on&nbsp;the&nbsp;bus<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;before&nbsp;the&nbsp;clock&nbsp;goes&nbsp;off&nbsp;again&nbsp;(bjd)&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msleep(1);&nbsp;&nbsp;//等待一下,因为LCD停止需要一点时间<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clk_disable(info-&gtclk);&nbsp;&nbsp;//关闭LCD的时钟<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />}<br />^_^,下面的代码就不用解释了吧!<br />static&nbsp;int&nbsp;s3c2410fb_resume(struct&nbsp;platform_device&nbsp;*dev)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;fb_info&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*fbinfo&nbsp;=&nbsp;platform_get_drvdata(dev);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;s3c2410fb_info&nbsp;*info&nbsp;=&nbsp;fbinfo-&gtpar;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clk_enable(info-&gtclk);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msleep(1);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s3c2410fb_init_registers(info);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />}<br /><br />OK,到现在为止,对于platform&nbsp;device的相关驱动就over了。不过精彩的还在后头哦!&nbsp;
initer 发表于 2009-4-2 13:52 | 显示全部楼层

感谢,这些**不错

  
msleep 发表于 2009-4-2 17:22 | 显示全部楼层

这些**很经典

  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

101

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部