android2.3.4下,linux2.6.36内核的lcd驱动

2012 年 3月 30日     星期五              


最近看了lcd驱动,本着不注解无真相的精神,写下android2.3.4下,linux2.6.36内核的lcd驱动

硬件平台:mini6410+4.3LCD
系统平台:android2.3.4+linux2.6.36
驱动文件:s3c-fb.c

我们这里主要分析s3c-fb.c中的probe函数, probe函数里最重要的是s3c_fb_probe_win函数

首先解释一个概念,很多书中有framebuffer这个概念,但是在三星的显示控制器文档或代码中,常出现win或window的概念,显示控制器可以控制0~5个windows,代码中分给它们分别编号win0, win1,win2......这里一张win或window就对应一个framebuffer, 每个framebuffer有自己的一个FBI(fb_info)结构,


代码中, 显示控制器是s3c_fb结构体, window是s3c_fb_win结构体。

代码中有两种data,一种是platform data(在板文件中定义),另一种是driver data(在驱动文件中定义),在它们各自的结构体里面,又可以分为两部份,一是用于sfb的data, 另一是用于win的data。

framebuffer是fb_info结构体,里面主要存储设置参数的数据结构有两个,fb_var_screeninfo和fb_fix_screeninfo结构体。

 


1、同IIC设备一样,首先需要在mach-mini6410.c 文件中配置和创建平台设备(platform),在linux2. 6设备模型中,关心总线,设备,驱动这三个实体,总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动。相反,在系统每注册一个驱动的时候,寻找与之匹配的设备,匹配是由总线来完成的。一个现实的Linux 设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI 等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC 系统中集成的独立的外设控制器、挂接在SoC 内存空间的外设等确不依附于此类总线。基于这一背景,Linux 发明了一种虚拟的总线,称为platform 总线。SOC系统中集成的独立外设单元(LCD,RTC,WDT等)都被当作平台设备来处理,而它们本身是字符型设备。其实可以和IIC设备比较一下,IIC的控制器为IIC适配器,LCD为LCD控制器(平台设备)。下面是mach-mini6410.c 文件中platform device的创建:

static struct platform_device *mini6410_devices[] __initdata = {
#ifdef CONFIG_MINI6410_SD_CH0
 &s3c_device_hsmmc0,
#endif
#ifdef CONFIG_MINI6410_SD_CH1
 &s3c_device_hsmmc1,
#endif
 &s3c_device_i2c0,
#ifdef CONFIG_S3C_DEV_I2C1
 &s3c_device_i2c1,
#endif
 &s3c_device_nand,
 &s3c_device_fb,     //这个就是LCD控制器结构体
 &s3c_device_ohci,
 &s3c_device_usb_hsotg,
#ifdef CONFIG_SND_S3C_SOC_AC97
 &s3c64xx_device_ac97,
#else
 &s3c64xx_device_iisv4,
#endif

 &mini6410_lcd_powerdev,
 &usb_mass_storage_device,

#ifdef CONFIG_DM9000
 &s3c_device_dm9000,
#endif
#ifdef CONFIG_S3C_ADC
 &s3c_device_adc,
#endif
#if defined(CONFIG_TOUCHSCREEN_MINI6410) || defined(CONFIG_SAMSUNG_DEV_TS)
 &s3c_device_ts,
#endif
 &s3c_device_wdt,
#ifdef CONFIG_S3C_DEV_RTC
 &s3c_device_rtc,
#endif
 &s3c_device_gpio_btns,
 &s3c_device_android_usb,

 /* Multimedia support */
#ifdef CONFIG_VIDEO_SAMSUNG
 &s3c_device_vpp,
 &s3c_device_mfc,
 &s3c_device_tvenc,
 &s3c_device_tvscaler,
 &s3c_device_rotator,
 &s3c_device_jpeg,
 &s3c_device_fimc0,
 &s3c_device_fimc1,
 &s3c_device_g2d,
 &s3c_device_g3d,
 &android_pmem_device,
#ifdef CONFIG_VIDEO_G3D
 &android_pmem_gpu1_device,
 &android_pmem_adsp_device,
#endif
#endif
};

可以看到平台设备可以包含很多控制器,这里需要添加&s3c_device_fb这个结构体,然后在static void __init mini6410_map_io(void)函数中增加两个函数
1) s3c_fb_set_platdata ( &mini6410_lcd_pdata );,其中的mini6410_lcd_pdata记录了LCD的机器信息(硬件特征),函数的作用为将LCD硬件特征赋值给平台设备的平台数据platrorm_data。其中mini6410_lcd_pdata为
static struct s3c_fb_platdata mini6410_lcd_pdata __initdata = {
 .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
 .win[0]  = &mini6410_fb_win0,//只定义了win【0】,其中包含了LCD设备的信息
         /* static struct s3c_fb_pd_win mini6410_fb_win0 = {
                       .win_mode = {
                      #if 0
                        .pixclock = 115440,
                      #endif
                        .left_margin = 0x03,
                        .right_margin = 0x02,
                        .upper_margin = 0x01,
                        .lower_margin = 0x01,
                        .hsync_len = 0x28,
                        .vsync_len = 0x01,
                        .xres  = 480,
                        .yres  = 272,
                       },
                        .max_bpp = 32,
                        .default_bpp = 16,
                      };*/
 .max_bpp = 32,
 .default_bpp = 16,
};
 .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
 .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
};
也就是将平台数据进行了赋值,以备后面的s3c-fb.c函数中使用
2)platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));将所有的平台设备添加到系统中,其中包括&s3c_device_fb,来看下这个结构体
struct platform_device s3c_device_fb = {
 .name    = "s3c-fb",  //设备名称,同driver匹配的时候要用
 .id    = -1,
 .num_resources   = ARRAY_SIZE(s3c_fb_resource),
 .resource   = s3c_fb_resource,
 .dev.dma_mask   = &s3c_device_fb.dev.coherent_dma_mask,
 .dev.coherent_dma_mask = 0xffffffffUL,
};
 其中的s3c_fb_resource为平台设备所要用的资源
 static struct resource s3c_fb_resource[] = {
 [0] = { //IO内存资源
  .start = S3C_PA_FB,
  .end   = S3C_PA_FB + SZ_16K - 1,
  .flags = IORESOURCE_MEM,
 },
 [1] = { //IRQ资源
  .start = IRQ_LCD_VSYNC,
  .end   = IRQ_LCD_VSYNC,
  .flags = IORESOURCE_IRQ,
 },
 [2] = {
  .start = IRQ_LCD_FIFO,
  .end   = IRQ_LCD_FIFO,
  .flags = IORESOURCE_IRQ,
 },
 [3] = {
  .start = IRQ_LCD_SYSTEM,
  .end   = IRQ_LCD_SYSTEM,
  .flags = IORESOURCE_IRQ,
 },
};
至此,LCD控制器平台设备创建完成


2、驱动文件s3c-fb.c
static int __init s3c_fb_init(void)
{
 return platform_driver_register(&s3c_fb_driver);
}
static struct platform_driver s3c_fb_driver = {
 .probe  = s3c_fb_probe,
 .remove  = __devexit_p(s3c_fb_remove),
 .suspend = s3c_fb_suspend,
 .resume  = s3c_fb_resume,
 .id_table = s3c_fb_driver_ids,
 .driver  = {
  .name = "s3c-fb",//用于寻找对应的平台设备,与mach-mini6410.c中定义的LCD平台设备相对应
  .owner = THIS_MODULE,
 },
};

static struct platform_device_id s3c_fb_driver_ids[] = {
 {
  .name  = "s3c-fb",
  .driver_data = (unsigned long)&s3c_fb_data_64xx,
 }, {
  .name  = "s5pc100-fb",
  .driver_data = (unsigned long)&s3c_fb_data_s5pc100,
 }, {
  .name  = "s5pv210-fb",
  .driver_data = (unsigned long)&s3c_fb_data_s5pv210,
 }, {
  .name  = "s3c2443-fb",
  .driver_data = (unsigned long)&s3c_fb_data_s3c2443,
 },
 {},
};
MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);

同IIC设备驱动一样,这里也有与mach-mini6410.c中相呼应的platform_device_id,另外注意此结构体中有一项driver_data,是进行了初始化的,在后面的probe函数中是要进行调用的,


首先进行平台驱动的注册,platform_driver_register(&s3c_fb_driver);此会导致平台驱动中的s3c_fb_probe函数(探测函数)被调用。这个探测函数会完成LCD硬件的初始化,FBI(帧缓存设备结构体,后面会说)参数的填充,注册显示缓冲区,并注册帧缓存设备。
static int __devinit s3c_fb_probe(struct platform_device *pdev)
{
 struct s3c_fb_driverdata *fbdrv;
 struct device *dev = &pdev->dev;
 struct s3c_fb_platdata *pd;
 struct s3c_fb *sfb;
 struct resource *res;
 int win;
 int ret = 0;

 fbdrv = (struct s3c_fb_driverdata *)platform_get_device_id(pdev)->driver_data; /*获取对应的driver data,也就是上面定义了的s3c_fb_data_64xx
                                                                                                                          static struct s3c_fb_driverdata s3c_fb_data_64xx = {
                               .variant = {
                                .nr_windows = 5,
                                .vidtcon = VIDTCON0,
                                .wincon  = WINCON(0),
                                .winmap  = WINxMAP(0),
                                .keycon  = WKEYCON,
                                .osd  = VIDOSD_BASE,
                                .osd_stride = 16,
                                .buf_start = VIDW_BUF_START(0),
                                .buf_size = VIDW_BUF_SIZE(0),
                                .buf_end = VIDW_BUF_END(0),
                              
                                .palette = {
                                 [0] = 0x400,
                                 [1] = 0x800,
                                 [2] = 0x300,
                                 [3] = 0x320,
                                 [4] = 0x340,
                                },
                              
                                .has_prtcon = 1,
                               },
                               .win[0] = &s3c_fb_data_64xx_wins[0],
                               .win[1] = &s3c_fb_data_64xx_wins[1],
                               .win[2] = &s3c_fb_data_64xx_wins[2],
                               .win[3] = &s3c_fb_data_64xx_wins[3],
                               .win[4] = &s3c_fb_data_64xx_wins[4],
                              };*/
 
 
 if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
  dev_err(dev, "too many windows, cannot attach\n");
  return -EINVAL;
 }

 pd = pdev->dev.platform_data; //将平台数据赋值,  在mach-mini6410.c中已经对平台数据进行了填充(s3c_fb_set_platdata),这次是将其转到s3c_fb_platdata结构中
 if (!pd) {
  dev_err(dev, "no platform data specified\n");
  return -EINVAL;
 }

 sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);//申请帧缓冲结构体空间
 if (!sfb) {
  dev_err(dev, "no memory for framebuffers\n");
  return -ENOMEM;
 }

 dev_dbg(dev, "allocate new framebuffer %p\n", sfb);

 sfb->dev = dev;  //对s3c-fb结构体进行填充
 sfb->pdata = pd;
 sfb->variant = fbdrv->variant;

 sfb->bus_clk = clk_get(dev, "lcd");
 if (IS_ERR(sfb->bus_clk)) {
  dev_err(dev, "failed to get bus clock\n");
  goto err_sfb;
 }

 clk_enable(sfb->bus_clk);

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//获得LCD控制器IO口内存资源
 
 if (!res) {
  dev_err(dev, "failed to find registers\n");
  ret = -ENOENT;
  goto err_clk;
 }

 sfb->regs_res = request_mem_region(res->start, resource_size(res),
        dev_name(dev));//sfb中regs_res指针重定向到申请到的IO内存资源中,其中的request_mem_region函数的释义为:
                                     . request_mem_region() -- I/O内存申请usr/src/linux-2.6.21.5/kernel/resource.c.request_mem_region() -- 将起始地址为[start, start+n-1]的资源插入根资源iomem_resource中。参数start是I/O内存资源的起始物理地址(是CPU的RAM物理地址空间中的物理地址),参数n指定I/O内存资源的大小。注: 调用request_mem_region()不是必须的,但是建议使用。
 if (!sfb->regs_res) {
  dev_err(dev, "failed to claim register region\n");
  ret = -ENOENT;
  goto err_clk;
 }

 sfb->regs = ioremap(res->start, resource_size(res));//将一个IO地址空间映射到内核的虚拟地址空间上去,其中res->start为IO空间(物理地址)首地址, resource_size(res)是需要映射的长度,另外应该返回值就是映射的虚拟地址的首地址(未得到证实)
 if (!sfb->regs) {
  dev_err(dev, "failed to map registers\n");
  ret = -ENXIO;
  goto err_req_region;
 }

 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);//获得LCD控制器IRQ内存资源(mach-mini6410.c中定义的 resource 中,flag为 IORESOURCE_IRQ的一共有三个,获得的是哪一个?看到0了吗?说明是第一个,也就是IRQ_LCD_VSYNC,帧同步中断)
 if (!res) {
  dev_err(dev, "failed to acquire irq resource\n");
  ret = -ENOENT;
  goto err_ioremap;
 }
 sfb->irq_no = res->start;
 ret = request_irq(sfb->irq_no, s3c_fb_irq,
     0, "s3c_fb", sfb); //中断注册  其中已经构建好的sfb作为参数进行传递
 if (ret) {
  dev_err(dev, "irq request failed\n");
  goto err_ioremap;
 }

 dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);

 /* setup gpio and output polarity controls */

 pd->setup_gpio();/*其实也就是调用s3c64xx_fb_gpio_setup_24bpp这个函数(在mach-mini6410.c中设置了平台数据,可以参照上面的1-1)的说明),也就是对LCD控制器用到的GPIO口进行了设置。具体入下:     extern void s3c64xx_fb_gpio_setup_24bpp(void)
                    {
                     unsigned int gpio;
                    
                     for (gpio = S3C64XX_GPI(0); gpio <= S3C64XX_GPI(15); gpio++) {
                      s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
                      s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
                     }
                    
                     for (gpio = S3C64XX_GPJ(0); gpio <= S3C64XX_GPJ(11); gpio++) {
                      s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
                      s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
                     }
                    }
                                                                               从字面意思上看,他是按24位色进行GPIO设置的*/

 writel(pd->vidcon1, sfb->regs + VIDCON1); //对VIDCON1寄存器进行设置,可以查看6410的spec进行查看(硬件层的东西)。

 /* zero all windows before we do anything */

 for (win = 0; win < fbdrv->variant.nr_windows; win++)
  s3c_fb_clear_win(sfb, win);/*static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
                {
                 void __iomem *regs = sfb->regs;
                 u32 reg;
                
                 writel(0, regs + sfb->variant.wincon + (win * 4));
                 writel(0, regs + VIDOSD_A(win, sfb->variant));
                 writel(0, regs + VIDOSD_B(win, sfb->variant));
                 writel(0, regs + VIDOSD_C(win, sfb->variant));
                 reg = readl(regs + SHADOWCON);
                 writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
                }
                */
 函数作用为将wincon寄存器以及VIDOSD寄存器全部清零,禁止update各个window的shadow。(这个具体要分析6410的spec)

 /* initialise colour key controls */
 for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
  void __iomem *regs = sfb->regs + sfb->variant.keycon;

  regs += (win * 8);
  writel(0xffffff, regs + WKEYCON0);
  writel(0xffffff, regs + WKEYCON1);
 }

 /* we have the register setup, start allocating framebuffers */

 for (win = 0; win < fbdrv->variant.nr_windows; win++) {
  if (!pd->win[win])//mach-mini6410.c文件的platform_data文件中只定义了win【0】所以,下面的s3c_fb_probe_win(sfb, win, fbdrv->win[win], &sfb->windows[win]);中,参数只传入了win【0】。
   continue;

  if (!pd->win[win]->win_mode.pixclock)
   s3c_fb_missing_pixclock(&pd->win[win]->win_mode);

  ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], &sfb->windows[win]); /*分配 及 注册framebuffer的重要函数
                                                                        static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
                                        struct s3c_fb_win_variant *variant,
                                        struct s3c_fb_win **res)
                              {
                               struct fb_var_screeninfo *var;
                               struct fb_videomode *initmode;
                               struct s3c_fb_pd_win *windata;
                               struct s3c_fb_win *win;
                               struct fb_info *fbinfo;
                               int palette_size;
                               int ret;
                              
                               dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
                                  初始化等待队列头
                               init_waitqueue_head(&sfb->vsync_info.wait);
                                  调色板大小 , 这方面内容我还不了解,为什么乘以4?
                               palette_size = variant->palette_sz * 4;
                                 分配fb_info结构体,返回一个fb_info结构体地址,这个结构体现在没什么内容,只赋值了par(win的起始地址)和device(也就是sfb->dev) (父设备)两个变量
                               fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
                                     palette_size * sizeof(u32), sfb->dev);
                               
                               if (!fbinfo) {
                                dev_err(sfb->dev, "failed to allocate framebuffer\n");
                                return -ENOENT;
                               }
                              
                               windata = sfb->pdata->win[win_no];
                               initmode = &windata->win_mode;
                              
                               WARN_ON(windata->max_bpp == 0);
                               WARN_ON(windata->win_mode.xres == 0);
                               WARN_ON(windata->win_mode.yres == 0);
                              
                               win = fbinfo->par;
                               *res = win;  --->par就是win的起始地址,现在把起始地址给*res,那么*res就是指向s3c_fb_win的指针
                               var = &fbinfo->var; ---> 现在fbinfo->var还是空的, 只是将地址给var而已
                               win->variant = *variant;   --->将win的参数填进win->variant里
                               win->fbinfo = fbinfo; ---> 让win->fbinfo指向这个FBI结构实体
                               win->parent = sfb;  ---> win的parent是显示控制器,所以它指向sfb结构体
                               win->windata = windata;  --->windata指向 platform data中win的部份
                               win->index = win_no;
                               win->palette_buffer = (u32 *)(win + 1); --->这个也不太理解?
                              
                               ret = s3c_fb_alloc_memory(sfb, win);//为framebuffer申请内存空间,这个函数在最后进行注解
                               if (ret) {
                                dev_err(sfb->dev, "failed to allocate display memory\n");
                                return ret;
                               }
                              
                               //setup the r/b/g positions for the window's palette
                               if (win->variant.palette_16bpp) {->设置调色板信息,由于之前传入的是win【0】所以,下面else中的内容
                                //Set RGB 5:6:5 as default
                                win->palette.r.offset = 11;
                                win->palette.r.length = 5;
                                win->palette.g.offset = 5;
                                win->palette.g.length = 6;
                                win->palette.b.offset = 0;
                                win->palette.b.length = 5;
                              
                               } else {
                                //Set 8bpp or 8bpp and 1bit alpha
                                win->palette.r.offset = 16;
                                win->palette.r.length = 8;
                                win->palette.g.offset = 8;
                                win->palette.g.length = 8;
                                win->palette.b.offset = 0;
                                win->palette.b.length = 8;
                               }
                              
                               // setup the initial video mode from the window
                               fb_videomode_to_var(&fbinfo->var, initmode);--> 给FBI填上各个参数
                              
                               fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
                               fbinfo->fix.accel = FB_ACCEL_NONE;
                               fbinfo->var.activate = FB_ACTIVATE_NOW;
                               fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
                               fbinfo->var.bits_per_pixel = windata->default_bpp; -->16位,mach-mini6410.c 中,platform_data定义的win【0】中进行的赋值(不明白为什么是16位,前面都是按24位设置的啊)
                               fbinfo->fbops  = &s3c_fb_ops; ---->对framebuffer的操作
                               fbinfo->flags  = FBINFO_FLAG_DEFAULT;
                               fbinfo->pseudo_palette  = &win->pseudo_palette;
                              
                               // prepare to actually start the framebuffer
                              
                               ret = s3c_fb_check_var(&fbinfo->var, fbinfo); -->检查可变参数
                               if (ret < 0) {
                                dev_err(sfb->dev, "check_var failed on initial video params\n");
                                return ret;
                               }
                              
                               // create initial colour map
                              
                               ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
                               if (ret == 0)
                                fb_set_cmap(&fbinfo->cmap, fbinfo);
                               else
                                dev_err(sfb->dev, "failed to allocate fb cmap\n");
                              
                               s3c_fb_set_par(fbinfo);
                              
                               dev_dbg(sfb->dev, "about to register framebuffer\n");
                              
                               //run the check_var and set_par on our configuration.
                              
                               ret = register_framebuffer(fbinfo);//最终注册FBI。在/dev/graphics下产生fb设备文件
                               if (ret < 0) {
                                dev_err(sfb->dev, "failed to register framebuffer\n");
                                return ret;
                               }
                              
                               dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
                              
                               return 0;
                              }
                              */
  if (ret < 0) {
   dev_err(dev, "failed to create window %d\n", win);
   for (; win >= 0; win--)
    s3c_fb_release_win(sfb, sfb->windows[win]);
   goto err_irq;
  }
 }

 platform_set_drvdata(pdev, sfb);// 将sfb 填入pdev->dev->p->driverdata 结构体中????????????????

 return 0;

err_irq:
 free_irq(sfb->irq_no, sfb);

err_ioremap:
 iounmap(sfb->regs);

err_req_region:
 release_resource(sfb->regs_res);
 kfree(sfb->regs_res);

err_clk:
 clk_disable(sfb->bus_clk);
 clk_put(sfb->bus_clk);

err_sfb:
 kfree(sfb);
 return ret;
}


附录:
1、s3c_fb_probe_win中的函数 s3c_fb_alloc_memory 为framebuffer申请内存空间
static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
      struct s3c_fb_win *win)
{
 struct s3c_fb_pd_win *windata = win->windata;//platform_data中的win部分,也就是win【0】
 unsigned int real_size, virt_size, size;
 struct fb_info *fbi = win->fbinfo;
 dma_addr_t map_dma;

 dev_dbg(sfb->dev, "allocating memory for display\n");

 real_size = windata->win_mode.xres * windata->win_mode.yres;//win[0]中的值,xres=480,yres=272.
 virt_size = windata->virtual_x * windata->virtual_y;//win[0]中并没有定义virtual_x、virtual_y。

 dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
  real_size, windata->win_mode.xres, windata->win_mode.yres,
  virt_size, windata->virtual_x, windata->virtual_y);

 size = (real_size > virt_size) ? real_size : virt_size;
 size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;//win【0】中定义的max_bpp=32
 size /= 8;

 fbi->fix.smem_len = size;//分配内存大小
 size = PAGE_ALIGN(size);//页对齐

 dev_dbg(sfb->dev, "want %u bytes for window\n", size);

 fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
        &map_dma, GFP_KERNEL);//分配framebuffer内存,关于为何要用dma_alloc_writecombine,在《linux设备驱动程序详解》的LCD驱动里有介绍
 
 if (!fbi->screen_base)
  return -ENOMEM;

 dev_dbg(sfb->dev, "mapped %x to %p\n",
  (unsigned int)map_dma, fbi->screen_base);

 memset(fbi->screen_base, 0x0, size);//为分配到的内存清零。
 fbi->fix.smem_start = map_dma;

 return 0;
}

 

.目前存在的问题点:1、在填充FBI结构体的fbinfo->var.bits_per_pixel时,填充的是16位,可之前6410寄存器设置的都是按24位进行设置的(fbinfo->var.bits_per_pixel = windata->default_bpp)。
                             2、在probe的s3c_fb_probe_win函数中进行了 register_framebuffer(fbinfo);此函数中调用了creat_device函数, 但是奇怪的是在驱动加载后并没有在/dev/下找到fb的相关设备文件,也没有主设备号为29的设备文件(平台设备主设备号均为29).
                             此问题已经解决,是因为在device_creat调用之前已经对设备类进行了定义fb_class = class_create(THIS_MODULE, "graphics");(fbmem.c文件中)所以设备文件的地址在/dev/graphics/下,一共定义了两个即fb0,fb1.
                              3、注意,以上程序中只是涉及到了,触摸屏平台设备驱动的编写,实际上I2C适配器也是平台设备,6410中沿用了2410的适配器驱动文件i2c-s3c2410.c(由于在mach-mini6410.c中的平台设备中定义了I2C的平台设备,其中定义了I2C适配器寄存器的起始位置和终止位置,而s3c2410的寄存器地址偏移同6410的相同,所以可以使用同一个适配器驱动文件)
       

你可能感兴趣的:(c,android,linux,windows,struct,平台)