帧设备驱动(二)

来源:互联网 发布:win10网络连接红叉断网 编辑:程序博客网 时间:2024/06/08 15:34

一是对LCD及其相关部件的初始化,包括画面缓冲区的创建和对DMA通道的设置;二是对画面缓冲区的读写,具体到代码为readwrite等系统调用接口。

 

这些都是由帧缓冲设备驱动来完成的。帧缓冲设备对应的设备文件通常为/dev/fb031Linux的帧缓冲设备的驱动主要基于两个文件:

 

  1)linux/include/linux/fb.h

 

  2)linux/drivers/video/fbmem.c

 

  帧缓冲设备属于字符设备,采用“文件层-驱动层”的接口方式。

文件fbmem.c中定义了帧缓冲设备的文件层接口file_operations结构体,它对应用程序可见,该结构体的定义如下:

 

 static const struct file_operations fb_fops = {

         .owner=  THIS_MODULE,

         .read=               fb_read,

         .write=    fb_write,

         .unlocked_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

         .llseek=   default_llseek,

};

在这个结构体中功能函数open()release()不需要底层的支持,而read()write()mmap()则需要调用fb-get-fix()fb-get-var()fb-set-var()(这些函数位于结构体fb-info中指针fbops指向的结构体变量中)等与底层LCD硬件相关的函数的支持。另一个功能函数是ioctl()ioctl()是设备驱动程序中对设备的I/O通道进行管理的函数,应用程序应用ioctl()系统调用来调用fb-get-fix()fb-get-var()fb-set-var()等方法来获得和设置结构体fb-infovarfixcmap等变量的信息。

 

  帧缓冲设备在驱动层所要做的工作仅仅是对Linux为帧缓冲的驱动层接口fb_info进行初始化,然后调用这两个函数对其注册或注销。

 

     帧缓冲设备驱动层接口直接对LCD设备硬件进行操作,而fbmem.c可以记录和管理多个底层设备驱动。

     

LCD控制器经常被集成到SOC上作为一个独立硬件模块而存在(成为platform_device,因此,模块加载函数中完成的只是注册平台驱动,而初始化FBI结构体中固定参数和可变参数,申请帧缓冲设备的显示缓冲区,注册缓冲区则交给探测函数完成。

 

int __init s3c2410fb_init(void)

{

         intret = platform_driver_register(&s3c2410fb_driver);

 

         if(ret == 0)

                   ret= platform_driver_register(&s3c2412fb_driver);

 

         returnret;

}

 

static void __exit s3c2410fb_cleanup(void)

{

         platform_driver_unregister(&s3c2410fb_driver);

         platform_driver_unregister(&s3c2412fb_driver);

}

 

module_init(s3c2410fb_init);使用insmod 或者modprobe命令加载时自动调用

module_exit(s3c2410fb_cleanup); 使用rmmod 卸载时自动调用

 MODULE_AUTHOR("ArnaudPatard <arnaud.patard@rtp-net.org>, "

               "Ben Dooks<ben-linux@fluff.org>");

MODULE_DESCRIPTION("Framebuffer driverfor the s3c2410");

MODULE_LICENSE("GPL");

MODULE_ALIAS("platform:s3c2410-lcd");

MODULE_ALIAS("platform:s3c2412-lcd");

对应的platform_driver结构体为:

static struct platform_drivers3c2410fb_driver = {

         .probe                =s3c2410fb_probe,

         .remove            = __devexit_p(s3c2410fb_remove),

         .suspend  = s3c2410fb_suspend,

         .resume            = s3c2410fb_resume,

         .driver                = {

                   .name       = "s3c2410-lcd", //驱动名

                   .owner     = THIS_MODULE,

         },

};

struct platform_device {

         constchar        * name;

         int              id;

        struct device    dev;

         u32            num_resources;

         structresource        * resource;

 

         conststruct platform_device_id     *id_entry;

 

         /*arch specific additions */

         structpdev_archdata      archdata;

};

 

static struct fb_ops s3c2410fb_ops = {

         .owner               = THIS_MODULE,

         .fb_check_var  = s3c2410fb_check_var,

         .fb_set_par      = s3c2410fb_set_par,

         .fb_blank = s3c2410fb_blank,

         .fb_setcolreg   = s3c2410fb_setcolreg,

         .fb_fillrect         = cfb_fillrect,

         .fb_copyarea   = cfb_copyarea,

         .fb_imageblit   = cfb_imageblit,

};

那么平台设备的资源呢?

 

/* LCD Controller */

 

 

static u64 s3c_device_lcd_dmamask =0xffffffffUL;

 

 

struct platform_device s3c_device_lcd = {

.name  = "s3c-lcd",

.id  = -1,设备编号,-1表示只有这样一个设备

.num_resources =ARRAY_SIZE(s3c_lcd_resource),

.resource  = s3c_lcd_resource,

.dev             = {

.dma_mask  =&s3c_device_lcd_dmamask,

.coherent_dma_mask= 0xffffffffUL

}

};

/*

 *  Probe平台驱动探测函数

 */

static int __devinit s3c2410fb_probe(structplatform_device *pdev)

{

         returns3c24xxfb_probe(pdev, DRV_S3C2410);

}

static int __devinit s3c24xxfb_probe(structplatform_device *pdev,

                                       enum s3c_drv_type drv_type)

{

         structs3c2410fb_info *info;

         structs3c2410fb_display *display;

         structfb_info *fbinfo;

         structs3c2410fb_mach_info *mach_info;

         structresource *res;

         intret;

         intirq;

         inti;

         intsize;

         u32lcdcon1;

 

         mach_info= pdev->dev.platform_data;

         if(mach_info == NULL) {

                   dev_err(&pdev->dev,

                            "noplatform data for lcd, cannot attach\n");

                   return-EINVAL;

         }

 

         if(mach_info->default_display >= mach_info->num_displays) {

                   dev_err(&pdev->dev,"default is %d but only %d displays\n",

                            mach_info->default_display,mach_info->num_displays);

                   return-EINVAL;

         }

 

         display= mach_info->displays + mach_info->default_display;

 

         irq= platform_get_irq(pdev, 0);

         if(irq < 0) {

                   dev_err(&pdev->dev,"no irq for device\n");

                   return-ENOENT;

         }

//分配fb_info空间

         fbinfo= framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);

         if(!fbinfo)

                   return-ENOMEM;

 

         platform_set_drvdata(pdev,fbinfo);

 

         info= fbinfo->par;

         info->dev= &pdev->dev;

         info->drv_type= drv_type;

 

         res= platform_get_resource(pdev, IORESOURCE_MEM, 0);

         if(res == NULL) {

                   dev_err(&pdev->dev,"failed to get memory registers\n");

                   ret= -ENXIO;

                   gotodealloc_fb;

         }

 

         size= (res->end - res->start) + 1;

         info->mem= request_mem_region(res->start, size, pdev->name);

         if(info->mem == NULL) {

                   dev_err(&pdev->dev,"failed to get memory region\n");

                   ret= -ENOENT;

                   gotodealloc_fb;

         }

 

         info->io= ioremap(res->start, size);

         if(info->io == NULL) {

                   dev_err(&pdev->dev,"ioremap() of registers failed\n");

                   ret= -ENXIO;

                   gotorelease_mem;

         }

 

         info->irq_base= info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE :S3C2410_LCDINTBASE);

 

         dprintk("devinit\n");

 

         strcpy(fbinfo->fix.id,driver_name);

 

         /*Stop the video */

         lcdcon1= readl(info->io + S3C2410_LCDCON1);

         writel(lcdcon1& ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);

 

         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;

 

         fbinfo->var.nonstd       =0;

         fbinfo->var.activate     =FB_ACTIVATE_NOW;

         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;

 

         for(i = 0; i < 256; i++)

                   info->palette_buffer[i]= PALETTE_BUFF_CLEAR;

 

         ret= request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);

         if(ret) {

                   dev_err(&pdev->dev,"cannot get irq %d - err %d\n", irq, ret);

                   ret= -EBUSY;

                   gotorelease_regs;

         }

 

         info->clk= clk_get(NULL, "lcd");

         if(IS_ERR(info->clk)) {

                   printk(KERN_ERR"failed to get lcd clock source\n");

                   ret= PTR_ERR(info->clk);

                   gotorelease_irq;

         }

 

         clk_enable(info->clk);

         dprintk("gotand enabled clock\n");

 

         msleep(1);

 

         info->clk_rate= clk_get_rate(info->clk);

 

         /*find maximum required memory size for display */

         for(i = 0; i < mach_info->num_displays; i++) {

                   unsignedlong smem_len = mach_info->displays[i].xres;

 

                   smem_len*= mach_info->displays[i].yres;

                   smem_len*= mach_info->displays[i].bpp;

                   smem_len>>= 3;

                   if(fbinfo->fix.smem_len < smem_len)

                            fbinfo->fix.smem_len= smem_len;

         }

 

 

         /*Initialize video memory */

         ret= s3c2410fb_map_video_memory(fbinfo);

         if(ret) {

                   printk(KERN_ERR"Failed to allocate video RAM: %d\n", ret);

                   ret= -ENOMEM;

                   gotorelease_clock;

         }

 

         dprintk("gotvideo memory\n");

 

         fbinfo->var.xres= display->xres;

         fbinfo->var.yres= display->yres;

         fbinfo->var.bits_per_pixel= display->bpp;

 

         s3c2410fb_init_registers(fbinfo);

    //检查可变参数

         s3c2410fb_check_var(&fbinfo->var,fbinfo);

 

         ret= s3c2410fb_cpufreq_register(info);

         if(ret < 0) {

                   dev_err(&pdev->dev,"Failed to register cpufreq\n");

                   gotofree_video_memory;

         }

  //注册FBI

         ret= register_framebuffer(fbinfo);

         if(ret < 0) {

                   printk(KERN_ERR"Failed to register framebuffer device: %d\n",

                            ret);

                   gotofree_cpufreq;

         }

 

         /*create device files */

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

         if(ret) {

                   printk(KERN_ERR"failed to add debug attribute\n");

         }

 

         printk(KERN_INFO"fb%d: %s frame buffer device\n",

                   fbinfo->node,fbinfo->fix.id);

 

         return0;

 

 free_cpufreq:

         s3c2410fb_cpufreq_deregister(info);

free_video_memory:

         s3c2410fb_unmap_video_memory(fbinfo);

release_clock:

         clk_disable(info->clk);

         clk_put(info->clk);

release_irq:

         free_irq(irq,info);

release_regs:

         iounmap(info->io);

release_mem:

         release_resource(info->mem);

         kfree(info->mem);

dealloc_fb:

         platform_set_drvdata(pdev,NULL);

         framebuffer_release(fbinfo);

         returnret;

}

static int __devexits3c2410fb_remove(struct platform_device *pdev)

{

         structfb_info *fbinfo = platform_get_drvdata(pdev);

         structs3c2410fb_info *info = fbinfo->par;

         intirq;

 

         unregister_framebuffer(fbinfo);//注销fb_info

         s3c2410fb_cpufreq_deregister(info);

 

         s3c2410fb_lcd_enable(info,0);

         msleep(1);

 

         s3c2410fb_unmap_video_memory(fbinfo);

 

         if(info->clk) {

                   clk_disable(info->clk);

                   clk_put(info->clk);

                   info->clk= NULL;

         }

 

         irq= platform_get_irq(pdev, 0);

         free_irq(irq,info);

 

         iounmap(info->io);

 

         release_resource(info->mem);

         kfree(info->mem);

 

         platform_set_drvdata(pdev,NULL);

         framebuffer_release(fbinfo);

 

         return0;

}

 

 

 

 

原创粉丝点击