• Framebuffer子系统【转】


    本文转载自:http://blog.csdn.net/av_geek/article/details/40897115

    本文将介绍Framebuffer子系统

    目标平台:TQ2440 CPU:s3c2440

    LCD设备:3.5英寸,分辨率320X240

    1. 概述

    Framebuffer,中文名字是帧缓冲,这个帧也就是一副图像所需要的数据。因此,帧缓冲其实就是LCD设备的驱动程序。Linux中,framebuffer子系统框架如下:

    核心层的代码以fbmem.c为主,核心层包括许多与具体硬件无关的代码,并且提供了API给用户空间。用户空间使用系统调用,系统调用会使用相应的API函数,最后会调用驱动层实现功能。对于不同的设备,驱动层的代码将有所不同。

    接下来的内容中,首先给出framerbuffer使用的数据结构;随后简单描述framerbuffer核心层;最后,针对S3C2440,对驱动代码进行分析。

    2. 数据结构

    2.1 fb_info 结构

      该结构是内核用于描述一个特定framebuffer设备。其中包含了几个重要的结构,将在下面介绍。

      下列代码位于include/linux/fb.h

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct fb_info {  
    2.     int node;  
    3.     int flags;  
    4.     struct mutex lock;      /* Lock for open/release/ioctl funcs */  
    5.     struct fb_var_screeninfo var;   /* Current var */  
    6.     struct fb_fix_screeninfo fix;   /* Current fix */  
    7.     struct fb_monspecs monspecs;    /* Current Monitor specs */  
    8.     struct work_struct queue;   /* Framebuffer event queue */  
    9.     struct fb_pixmap pixmap;    /* Image hardware mapper */  
    10.     struct fb_pixmap sprite;    /* Cursor hardware mapper */  
    11.     struct fb_cmap cmap;        /* Current cmap */  
    12.     struct list_head modelist;      /* mode list */  
    13.     struct fb_videomode *mode;  /* current mode */  
    14.   
    15. #ifdef CONFIG_FB_BACKLIGHT   
    16.     /* assigned backlight device */  
    17.     /* set before framebuffer registration,  
    18.        remove after unregister */  
    19.     struct backlight_device *bl_dev;  
    20.   
    21.     /* Backlight level curve */  
    22.     struct mutex bl_curve_mutex;      
    23.     u8 bl_curve[FB_BACKLIGHT_LEVELS];  
    24. #endif   
    25. #ifdef CONFIG_FB_DEFERRED_IO   
    26.     struct delayed_work deferred_work;  
    27.     struct fb_deferred_io *fbdefio;  
    28. #endif   
    29.   
    30.     struct fb_ops *fbops;  
    31.     struct device *device;      /* This is the parent */  
    32.     struct device *dev;     /* This is this fb device */  
    33.     int class_flag;                    /* private sysfs flags */  
    34. #ifdef CONFIG_FB_TILEBLITTING   
    35.     struct fb_tile_ops *tileops;    /* Tile Blitting */  
    36. #endif   
    37.     char __iomem *screen_base;  /* Virtual address */  
    38.     unsigned long screen_size;  /* Amount of ioremapped VRAM or 0 */   
    39.     void *pseudo_palette;       /* Fake palette of 16 colors */   
    40. #define FBINFO_STATE_RUNNING    0   
    41. #define FBINFO_STATE_SUSPENDED  1   
    42.     u32 state;          /* Hardware state i.e suspend */  
    43.     void *fbcon_par;                /* fbcon use-only private area */  
    44.     /* From here on everything is device dependent */  
    45.     void *par;    
    46. };  
    [cpp] view plain copy
     
    1. struct fb_info {  
    2.     int node;  
    3.     int flags;  
    4.     struct mutex lock;      /* Lock for open/release/ioctl funcs */  
    5.     struct fb_var_screeninfo var;   /* Current var */  
    6.     struct fb_fix_screeninfo fix;   /* Current fix */  
    7.     struct fb_monspecs monspecs;    /* Current Monitor specs */  
    8.     struct work_struct queue;   /* Framebuffer event queue */  
    9.     struct fb_pixmap pixmap;    /* Image hardware mapper */  
    10.     struct fb_pixmap sprite;    /* Cursor hardware mapper */  
    11.     struct fb_cmap cmap;        /* Current cmap */  
    12.     struct list_head modelist;      /* mode list */  
    13.     struct fb_videomode *mode;  /* current mode */  
    14.   
    15. #ifdef CONFIG_FB_BACKLIGHT  
    16.     /* assigned backlight device */  
    17.     /* set before framebuffer registration,  
    18.        remove after unregister */  
    19.     struct backlight_device *bl_dev;  
    20.   
    21.     /* Backlight level curve */  
    22.     struct mutex bl_curve_mutex;      
    23.     u8 bl_curve[FB_BACKLIGHT_LEVELS];  
    24. #endif  
    25. #ifdef CONFIG_FB_DEFERRED_IO  
    26.     struct delayed_work deferred_work;  
    27.     struct fb_deferred_io *fbdefio;  
    28. #endif  
    29.   
    30.     struct fb_ops *fbops;  
    31.     struct device *device;      /* This is the parent */  
    32.     struct device *dev;     /* This is this fb device */  
    33.     int class_flag;                    /* private sysfs flags */  
    34. #ifdef CONFIG_FB_TILEBLITTING  
    35.     struct fb_tile_ops *tileops;    /* Tile Blitting */  
    36. #endif  
    37.     char __iomem *screen_base;  /* Virtual address */  
    38.     unsigned long screen_size;  /* Amount of ioremapped VRAM or 0 */   
    39.     void *pseudo_palette;       /* Fake palette of 16 colors */   
    40. #define FBINFO_STATE_RUNNING    0  
    41. #define FBINFO_STATE_SUSPENDED  1  
    42.     u32 state;          /* Hardware state i.e suspend */  
    43.     void *fbcon_par;                /* fbcon use-only private area */  
    44.     /* From here on everything is device dependent */  
    45.     void *par;    
    46. };  

     

    2.2 fb_fix_screeninfo结构

      该数据结构是不可改变的,也就是说用户空间不能改变该结构中的任何成员,在核心层我们将会看到这点。

      下列代码位于include/linux/fb.h

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct fb_fix_screeninfo {  
    2.     char id[16];            /* identification string eg "TT Builtin" */  
    3.     unsigned long smem_start;   /* Start of frame buffer mem */  
    4.                     /* (physical address) */  
    5.     __u32 smem_len;         /* Length of frame buffer mem */  
    6.     __u32 type;         /* see FB_TYPE_*        */  
    7.     __u32 type_aux;         /* Interleave for interleaved Planes */  
    8.     __u32 visual;           /* see FB_VISUAL_*      */   
    9.     __u16 xpanstep;         /* zero if no hardware panning  */  
    10.     __u16 ypanstep;         /* zero if no hardware panning  */  
    11.     __u16 ywrapstep;        /* zero if no hardware ywrap    */  
    12.     __u32 line_length;      /* length of a line in bytes    */  
    13.     unsigned long mmio_start;   /* Start of Memory Mapped I/O   */  
    14.                     /* (physical address) */  
    15.     __u32 mmio_len;         /* Length of Memory Mapped I/O  */  
    16.     __u32 accel;            /* Indicate to driver which */  
    17.                     /*  specific chip/card we have  */  
    18.     __u16 reserved[3];      /* Reserved for future compatibility */  
    19. };  
    [cpp] view plain copy
     
    1. struct fb_fix_screeninfo {  
    2.     char id[16];            /* identification string eg "TT Builtin" */  
    3.     unsigned long smem_start;   /* Start of frame buffer mem */  
    4.                     /* (physical address) */  
    5.     __u32 smem_len;         /* Length of frame buffer mem */  
    6.     __u32 type;         /* see FB_TYPE_*        */  
    7.     __u32 type_aux;         /* Interleave for interleaved Planes */  
    8.     __u32 visual;           /* see FB_VISUAL_*      */   
    9.     __u16 xpanstep;         /* zero if no hardware panning  */  
    10.     __u16 ypanstep;         /* zero if no hardware panning  */  
    11.     __u16 ywrapstep;        /* zero if no hardware ywrap    */  
    12.     __u32 line_length;      /* length of a line in bytes    */  
    13.     unsigned long mmio_start;   /* Start of Memory Mapped I/O   */  
    14.                     /* (physical address) */  
    15.     __u32 mmio_len;         /* Length of Memory Mapped I/O  */  
    16.     __u32 accel;            /* Indicate to driver which */  
    17.                     /*  specific chip/card we have  */  
    18.     __u16 reserved[3];      /* Reserved for future compatibility */  
    19. };  

    2.3 fb_var_screeninfo结构

      该数据结构是可以改变的,也就是说用户空间可以改变该结构中的成员。该数据结构中的很多成员就由板级信息复制而来,在驱动代码中我们将会看到这点。

      下列代码位于include/linux/fb.h

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct fb_var_screeninfo {  
    2.     __u32 xres;         /* visible resolution       */  
    3.     __u32 yres;  
    4.     __u32 xres_virtual;     /* virtual resolution       */  
    5.     __u32 yres_virtual;  
    6.     __u32 xoffset;          /* offset from virtual to visible */  
    7.     __u32 yoffset;          /* resolution           */  
    8.   
    9.     __u32 bits_per_pixel;       /* guess what           */  
    10.     __u32 grayscale;        /* != 0 Graylevels instead of colors */  
    11.   
    12.     struct fb_bitfield red;     /* bitfield in fb mem if true color, */  
    13.     struct fb_bitfield green;   /* else only length is significant */  
    14.     struct fb_bitfield blue;  
    15.     struct fb_bitfield transp;  /* transparency         */    
    16.   
    17.     __u32 nonstd;           /* != 0 Non standard pixel format */  
    18.   
    19.     __u32 activate;         /* see FB_ACTIVATE_*        */  
    20.   
    21.     __u32 height;           /* height of picture in mm    */  
    22.     __u32 width;            /* width of picture in mm     */  
    23.   
    24.     __u32 accel_flags;      /* (OBSOLETE) see fb_info.flags */  
    25.   
    26.     /* Timing: All values in pixclocks, except pixclock (of course) */  
    27.     __u32 pixclock;         /* pixel clock in ps (pico seconds) */  
    28.     __u32 left_margin;      /* time from sync to picture    */  
    29.     __u32 right_margin;     /* time from picture to sync    */  
    30.     __u32 upper_margin;     /* time from sync to picture    */  
    31.     __u32 lower_margin;  
    32.     __u32 hsync_len;        /* length of horizontal sync    */  
    33.     __u32 vsync_len;        /* length of vertical sync  */  
    34.     __u32 sync;         /* see FB_SYNC_*        */  
    35.     __u32 vmode;            /* see FB_VMODE_*       */  
    36.     __u32 rotate;           /* angle we rotate counter clockwise */  
    37.     __u32 reserved[5];      /* Reserved for future compatibility */  
    38. };  
    [cpp] view plain copy
     
    1. struct fb_var_screeninfo {  
    2.     __u32 xres;         /* visible resolution       */  
    3.     __u32 yres;  
    4.     __u32 xres_virtual;     /* virtual resolution       */  
    5.     __u32 yres_virtual;  
    6.     __u32 xoffset;          /* offset from virtual to visible */  
    7.     __u32 yoffset;          /* resolution           */  
    8.   
    9.     __u32 bits_per_pixel;       /* guess what           */  
    10.     __u32 grayscale;        /* != 0 Graylevels instead of colors */  
    11.   
    12.     struct fb_bitfield red;     /* bitfield in fb mem if true color, */  
    13.     struct fb_bitfield green;   /* else only length is significant */  
    14.     struct fb_bitfield blue;  
    15.     struct fb_bitfield transp;  /* transparency         */    
    16.   
    17.     __u32 nonstd;           /* != 0 Non standard pixel format */  
    18.   
    19.     __u32 activate;         /* see FB_ACTIVATE_*        */  
    20.   
    21.     __u32 height;           /* height of picture in mm    */  
    22.     __u32 width;            /* width of picture in mm     */  
    23.   
    24.     __u32 accel_flags;      /* (OBSOLETE) see fb_info.flags */  
    25.   
    26.     /* Timing: All values in pixclocks, except pixclock (of course) */  
    27.     __u32 pixclock;         /* pixel clock in ps (pico seconds) */  
    28.     __u32 left_margin;      /* time from sync to picture    */  
    29.     __u32 right_margin;     /* time from picture to sync    */  
    30.     __u32 upper_margin;     /* time from sync to picture    */  
    31.     __u32 lower_margin;  
    32.     __u32 hsync_len;        /* length of horizontal sync    */  
    33.     __u32 vsync_len;        /* length of vertical sync  */  
    34.     __u32 sync;         /* see FB_SYNC_*        */  
    35.     __u32 vmode;            /* see FB_VMODE_*       */  
    36.     __u32 rotate;           /* angle we rotate counter clockwise */  
    37.     __u32 reserved[5];      /* Reserved for future compatibility */  
    38. };  

    2.4 fb_ops结构

      该结构描述了用于fb_info的方法,这些方法中有些是要驱动程序提供的,而有些可以使用内核提供的方法。

     下列代码位于include/linux/fb.h

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* 
    2.  * Frame buffer operations 
    3.  * 
    4.  * LOCKING NOTE: those functions must _ALL_ be called with the console 
    5.  * semaphore held, this is the only suitable locking mechanism we have 
    6.  * in 2.6. Some may be called at interrupt time at this point though. 
    7.  */  
    8.   
    9. struct fb_ops {  
    10.     /* open/release and usage marking */  
    11.     struct module *owner;  
    12.     int (*fb_open)(struct fb_info *info, int user);  
    13.     int (*fb_release)(struct fb_info *info, int user);  
    14.   
    15.     /* For framebuffers with strange non linear layouts or that do not 
    16.      * work with normal memory mapped access 
    17.      */  
    18.     ssize_t (*fb_read)(struct fb_info *info, char __user *buf,  
    19.                size_t count, loff_t *ppos);  
    20.     ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,  
    21.                 size_t count, loff_t *ppos);  
    22.   
    23.     /* checks var and eventually tweaks it to something supported, 
    24.      * DO NOT MODIFY PAR */  
    25.     int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);  
    26.   
    27.     /* set the video mode according to info->var */  
    28.     int (*fb_set_par)(struct fb_info *info);  
    29.   
    30.     /* set color register */  
    31.     int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,  
    32.                 unsigned blue, unsigned transp, struct fb_info *info);  
    33.   
    34.     /* set color registers in batch */  
    35.     int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);  
    36.   
    37.     /* blank display */  
    38.     int (*fb_blank)(int blank, struct fb_info *info);  
    39.   
    40.     /* pan display */  
    41.     int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);  
    42.   
    43.     /* Draws a rectangle */  
    44.     void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);  
    45.     /* Copy data from area to another */  
    46.     void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);  
    47.     /* Draws a image to the display */  
    48.     void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);  
    49.   
    50.     /* Draws cursor */  
    51.     int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);  
    52.   
    53.     /* Rotates the display */  
    54.     void (*fb_rotate)(struct fb_info *info, int angle);  
    55.   
    56.     /* wait for blit idle, optional */  
    57.     int (*fb_sync)(struct fb_info *info);  
    58.   
    59.     /* perform fb specific ioctl (optional) */  
    60.     int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,  
    61.             unsigned long arg);  
    62.   
    63.     /* Handle 32bit compat ioctl (optional) */  
    64.     int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,  
    65.             unsigned long arg);  
    66.   
    67.     /* perform fb specific mmap */  
    68.     int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);  
    69.   
    70.     /* save current hardware state */  
    71.     void (*fb_save_state)(struct fb_info *info);  
    72.   
    73.     /* restore saved state */  
    74.     void (*fb_restore_state)(struct fb_info *info);  
    75.   
    76.     /* get capability given var */  
    77.     void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,  
    78.                 struct fb_var_screeninfo *var);  
    79. };  
    [cpp] view plain copy
     
    1. /* 
    2.  * Frame buffer operations 
    3.  * 
    4.  * LOCKING NOTE: those functions must _ALL_ be called with the console 
    5.  * semaphore held, this is the only suitable locking mechanism we have 
    6.  * in 2.6. Some may be called at interrupt time at this point though. 
    7.  */  
    8.   
    9. struct fb_ops {  
    10.     /* open/release and usage marking */  
    11.     struct module *owner;  
    12.     int (*fb_open)(struct fb_info *info, int user);  
    13.     int (*fb_release)(struct fb_info *info, int user);  
    14.   
    15.     /* For framebuffers with strange non linear layouts or that do not 
    16.      * work with normal memory mapped access 
    17.      */  
    18.     ssize_t (*fb_read)(struct fb_info *info, char __user *buf,  
    19.                size_t count, loff_t *ppos);  
    20.     ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,  
    21.                 size_t count, loff_t *ppos);  
    22.   
    23.     /* checks var and eventually tweaks it to something supported, 
    24.      * DO NOT MODIFY PAR */  
    25.     int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);  
    26.   
    27.     /* set the video mode according to info->var */  
    28.     int (*fb_set_par)(struct fb_info *info);  
    29.   
    30.     /* set color register */  
    31.     int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,  
    32.                 unsigned blue, unsigned transp, struct fb_info *info);  
    33.   
    34.     /* set color registers in batch */  
    35.     int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);  
    36.   
    37.     /* blank display */  
    38.     int (*fb_blank)(int blank, struct fb_info *info);  
    39.   
    40.     /* pan display */  
    41.     int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);  
    42.   
    43.     /* Draws a rectangle */  
    44.     void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);  
    45.     /* Copy data from area to another */  
    46.     void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);  
    47.     /* Draws a image to the display */  
    48.     void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);  
    49.   
    50.     /* Draws cursor */  
    51.     int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);  
    52.   
    53.     /* Rotates the display */  
    54.     void (*fb_rotate)(struct fb_info *info, int angle);  
    55.   
    56.     /* wait for blit idle, optional */  
    57.     int (*fb_sync)(struct fb_info *info);  
    58.   
    59.     /* perform fb specific ioctl (optional) */  
    60.     int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,  
    61.             unsigned long arg);  
    62.   
    63.     /* Handle 32bit compat ioctl (optional) */  
    64.     int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,  
    65.             unsigned long arg);  
    66.   
    67.     /* perform fb specific mmap */  
    68.     int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);  
    69.   
    70.     /* save current hardware state */  
    71.     void (*fb_save_state)(struct fb_info *info);  
    72.   
    73.     /* restore saved state */  
    74.     void (*fb_restore_state)(struct fb_info *info);  
    75.   
    76.     /* get capability given var */  
    77.     void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,  
    78.                 struct fb_var_screeninfo *var);  
    79. };  

    3. frambuffer核心层

    首先来看下frmaebuffer子系统的初始化函数。

    3.1 fbmem_init和fbmem_exit

    下列代码位于drivers/video/fbmem.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.  *  fbmem_init - init frame buffer subsystem 
    3.  * 
    4.  *  Initialize the frame buffer subsystem. 
    5.  * 
    6.  *  NOTE: This function is _only_ to be called by drivers/char/mem.c. 
    7.  * 
    8.  */  
    9.   
    10. static int __init  
    11. fbmem_init(void)  
    12. {  
    13.     proc_create("fb", 0, NULL, &fb_proc_fops);  
    14.   
    15.     if (register_chrdev(FB_MAJOR,"fb",&fb_fops))        /*注册字符设备,major=29*/  
    16.         printk("unable to get major %d for fb devs ", FB_MAJOR);  
    17.   
    18.     fb_class = class_create(THIS_MODULE, "graphics");   /*创建类*/  
    19.     if (IS_ERR(fb_class)) {  
    20.         printk(KERN_WARNING "Unable to create fb class; errno = %ld ", PTR_ERR(fb_class));  
    21.         fb_class = NULL;  
    22.     }  
    23.     return 0;  
    24. }  
    25.   
    26. #ifdef MODULE   
    27. module_init(fbmem_init);  
    28. static void __exit  
    29. fbmem_exit(void)  
    30. {  
    31.     remove_proc_entry("fb", NULL);  
    32.     class_destroy(fb_class);  
    33.     unregister_chrdev(FB_MAJOR, "fb");  
    34. }  
    35.   
    36. module_exit(fbmem_exit);  
    37. MODULE_LICENSE("GPL");  
    38. MODULE_DESCRIPTION("Framebuffer base");  
    39. #else   
    40. subsys_initcall(fbmem_init);  
    41. #endif   
    42.   
    43. static const struct file_operations fb_fops = {  
    44.     .owner =    THIS_MODULE,  
    45.     .read =        fb_read,  
    46.     .write =    fb_write,  
    47.     .unlocked_ioctl = fb_ioctl,  
    48. #ifdef CONFIG_COMPAT   
    49.     .compat_ioctl = fb_compat_ioctl,  
    50. #endif   
    51.     .mmap =        fb_mmap,  
    52.     .open =        fb_open,  
    53.     .release =    fb_release,  
    54. #ifdef HAVE_ARCH_FB_UNMAPPED_AREA   
    55.     .get_unmapped_area = get_fb_unmapped_area,  
    56. #endif   
    57. #ifdef CONFIG_FB_DEFERRED_IO   
    58.     .fsync =    fb_deferred_io_fsync,  
    59. #endif   
    60. };  
    [cpp] view plain copy
     
    1. /** 
    2.  *  fbmem_init - init frame buffer subsystem 
    3.  * 
    4.  *  Initialize the frame buffer subsystem. 
    5.  * 
    6.  *  NOTE: This function is _only_ to be called by drivers/char/mem.c. 
    7.  * 
    8.  */  
    9.   
    10. static int __init  
    11. fbmem_init(void)  
    12. {  
    13.     proc_create("fb", 0, NULL, &fb_proc_fops);  
    14.   
    15.     if (register_chrdev(FB_MAJOR,"fb",&fb_fops))        /*注册字符设备,major=29*/  
    16.         printk("unable to get major %d for fb devs ", FB_MAJOR);  
    17.   
    18.     fb_class = class_create(THIS_MODULE, "graphics");   /*创建类*/  
    19.     if (IS_ERR(fb_class)) {  
    20.         printk(KERN_WARNING "Unable to create fb class; errno = %ld ", PTR_ERR(fb_class));  
    21.         fb_class = NULL;  
    22.     }  
    23.     return 0;  
    24. }  
    25.   
    26. #ifdef MODULE  
    27. module_init(fbmem_init);  
    28. static void __exit  
    29. fbmem_exit(void)  
    30. {  
    31.     remove_proc_entry("fb", NULL);  
    32.     class_destroy(fb_class);  
    33.     unregister_chrdev(FB_MAJOR, "fb");  
    34. }  
    35.   
    36. module_exit(fbmem_exit);  
    37. MODULE_LICENSE("GPL");  
    38. MODULE_DESCRIPTION("Framebuffer base");  
    39. #else  
    40. subsys_initcall(fbmem_init);  
    41. #endif  
    42.   
    43. static const struct file_operations fb_fops = {  
    44.     .owner =    THIS_MODULE,  
    45.     .read =        fb_read,  
    46.     .write =    fb_write,  
    47.     .unlocked_ioctl = fb_ioctl,  
    48. #ifdef CONFIG_COMPAT  
    49.     .compat_ioctl = fb_compat_ioctl,  
    50. #endif  
    51.     .mmap =        fb_mmap,  
    52.     .open =        fb_open,  
    53.     .release =    fb_release,  
    54. #ifdef HAVE_ARCH_FB_UNMAPPED_AREA  
    55.     .get_unmapped_area = get_fb_unmapped_area,  
    56. #endif  
    57. #ifdef CONFIG_FB_DEFERRED_IO  
    58.     .fsync =    fb_deferred_io_fsync,  
    59. #endif  
    60. };  


    我们看到,如果不是作为模块,那么该初始化程序将在subsys_initcall阶段被调用。初始化时,仅仅注册了一个字符设备,并创建了一个类。通过字符设备,提供了API给用户空间,包open,release,write,read等。

    随后我们看看如何分配一个fb_info结构。

    3.2 framebuffer_alloc

     

    下列代码位于drivers/video/fbmem.c

     

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.  * framebuffer_alloc - creates a new frame buffer info structure 
    3.  * 
    4.  * @size: size of driver private data, can be zero 
    5.  * @dev: pointer to the device for this fb, this can be NULL 
    6.  * 
    7.  * Creates a new frame buffer info structure. Also reserves @size bytes 
    8.  * for driver private data (info->par). info->par (if any) will be 
    9.  * aligned to sizeof(long). 
    10.  * 
    11.  * Returns the new structure, or NULL if an error occured. 
    12.  * 
    13.  */  
    14. struct fb_info *framebuffer_alloc(size_t size, struct device *dev)  
    15. {  
    16. #define BYTES_PER_LONG (BITS_PER_LONG/8)   
    17. #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))   
    18.     int fb_info_size = sizeof(struct fb_info);  
    19.     struct fb_info *info;  
    20.     char *p;  
    21.   
    22.     if (size)  
    23.         fb_info_size += PADDING;  
    24.   
    25.     p = kzalloc(fb_info_size + size, GFP_KERNEL);  
    26.   
    27.     if (!p)  
    28.         return NULL;  
    29.   
    30.     info = (struct fb_info *) p;  
    31.   
    32.     if (size)  
    33.         info->par = p + fb_info_size;  
    34.   
    35.     info->device = dev;  
    36.   
    37. #ifdef CONFIG_FB_BACKLIGHT   
    38.     mutex_init(&info->bl_curve_mutex);  
    39. #endif   
    40.   
    41.     return info;  
    42. #undef PADDING   
    43. #undef BYTES_PER_LONG   
    44. }  
    45. EXPORT_SYMBOL(framebuffer_alloc);  
    [cpp] view plain copy
     
    1. /** 
    2.  * framebuffer_alloc - creates a new frame buffer info structure 
    3.  * 
    4.  * @size: size of driver private data, can be zero 
    5.  * @dev: pointer to the device for this fb, this can be NULL 
    6.  * 
    7.  * Creates a new frame buffer info structure. Also reserves @size bytes 
    8.  * for driver private data (info->par). info->par (if any) will be 
    9.  * aligned to sizeof(long). 
    10.  * 
    11.  * Returns the new structure, or NULL if an error occured. 
    12.  * 
    13.  */  
    14. struct fb_info *framebuffer_alloc(size_t size, struct device *dev)  
    15. {  
    16. #define BYTES_PER_LONG (BITS_PER_LONG/8)  
    17. #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))  
    18.     int fb_info_size = sizeof(struct fb_info);  
    19.     struct fb_info *info;  
    20.     char *p;  
    21.   
    22.     if (size)  
    23.         fb_info_size += PADDING;  
    24.   
    25.     p = kzalloc(fb_info_size + size, GFP_KERNEL);  
    26.   
    27.     if (!p)  
    28.         return NULL;  
    29.   
    30.     info = (struct fb_info *) p;  
    31.   
    32.     if (size)  
    33.         info->par = p + fb_info_size;  
    34.   
    35.     info->device = dev;  
    36.   
    37. #ifdef CONFIG_FB_BACKLIGHT  
    38.     mutex_init(&info->bl_curve_mutex);  
    39. #endif  
    40.   
    41.     return info;  
    42. #undef PADDING  
    43. #undef BYTES_PER_LONG  
    44. }  
    45. EXPORT_SYMBOL(framebuffer_alloc);  

    在进行分配时,根据参数size的大小,分配了b_info_size + size的空间,然后让fb_info->par指向size的空间。因此par所指向的空间可视为设备特有的数据。

    在分配了fb_info结构之后,需要将它注册到内核中。注册由register_framebuffer完成。我们来看下。

    3.3 register_framebuffer

    下列代码位于drivers/video/fbmem.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.  *  register_framebuffer - registers a frame buffer device 
    3.  *  @fb_info: frame buffer info structure 
    4.  * 
    5.  *  Registers a frame buffer device @fb_info. 
    6.  * 
    7.  *  Returns negative errno on error, or zero for success. 
    8.  * 
    9.  */  
    10.   
    11. int  
    12. register_framebuffer(struct fb_info *fb_info)  
    13. {  
    14.     int i;  
    15.     struct fb_event event;  
    16.     struct fb_videomode mode;  
    17.   
    18.     if (num_registered_fb == FB_MAX) /*最多32个FB*/  
    19.         return -ENXIO;  
    20.   
    21.     if (fb_check_foreignness(fb_info))  
    22.         return -ENOSYS;  
    23.   
    24.     num_registered_fb++;        /*对注册的FB计数*/  
    25.     /*寻找第一个空位*/  
    26.     for (i = 0 ; i < FB_MAX; i++)/*FB_MAX=32,也就是最多32个framebuffer*/  
    27.         if (!registered_fb[i])  /*struct fb_info *registered_fb[FB_MAX]*/  
    28.             break;  
    29.     fb_info->node = i;  
    30.     mutex_init(&fb_info->lock);  /*初始化互斥体*/  
    31.   
    32.     fb_info->dev = device_create(fb_class, fb_info->device,/*创建设备节点,节点名为fbx*/  
    33.                      MKDEV(FB_MAJOR, i), NULL, "fb%d", i);  
    34.     if (IS_ERR(fb_info->dev)) {  
    35.         /* Not fatal */  
    36.         printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld ", i, PTR_ERR(fb_info->dev));  
    37.         fb_info->dev = NULL;  
    38.     } else  
    39.         fb_init_device(fb_info);    /*初始化,在class/graphics/fbx/下创建设备属性*/  
    40.   
    41.     if (fb_info->pixmap.addr == NULL) {  
    42.         fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);/*分配内存,1024 * 8字节*/  
    43.         if (fb_info->pixmap.addr) {  
    44.             fb_info->pixmap.size = FBPIXMAPSIZE;  
    45.             fb_info->pixmap.buf_align = 1;  
    46.             fb_info->pixmap.scan_align = 1;  
    47.             fb_info->pixmap.access_align = 32;  
    48.             fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;  
    49.         }  
    50.     }     
    51.     fb_info->pixmap.offset = 0;  
    52.   
    53.     if (!fb_info->pixmap.blit_x)  
    54.         fb_info->pixmap.blit_x = ~(u32)0;  
    55.   
    56.     if (!fb_info->pixmap.blit_y)  
    57.         fb_info->pixmap.blit_y = ~(u32)0;  
    58.   
    59.     if (!fb_info->modelist.prev || !fb_info->modelist.next)   /*该链表没有指向其他节点*/  
    60.         INIT_LIST_HEAD(&fb_info->modelist);  /*初始化链表头*/  
    61.   
    62.     fb_var_to_videomode(&mode, &fb_info->var);/*转换fb_var_screeninfo成fb_videomode*/  
    63.     fb_add_videomode(&mode, &fb_info->modelist);/*添加mode至链表中*/  
    64.     registered_fb[i] = fb_info;  
    65.   
    66.     event.info = fb_info;  
    67.     if (!lock_fb_info(fb_info))  
    68.         return -ENODEV;  
    69.     fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);/*???*/  
    70.     unlock_fb_info(fb_info);  
    71.     return 0;  
    72. }  
    [cpp] view plain copy
     
    1. /** 
    2.  *  register_framebuffer - registers a frame buffer device 
    3.  *  @fb_info: frame buffer info structure 
    4.  * 
    5.  *  Registers a frame buffer device @fb_info. 
    6.  * 
    7.  *  Returns negative errno on error, or zero for success. 
    8.  * 
    9.  */  
    10.   
    11. int  
    12. register_framebuffer(struct fb_info *fb_info)  
    13. {  
    14.     int i;  
    15.     struct fb_event event;  
    16.     struct fb_videomode mode;  
    17.   
    18.     if (num_registered_fb == FB_MAX) /*最多32个FB*/  
    19.         return -ENXIO;  
    20.   
    21.     if (fb_check_foreignness(fb_info))  
    22.         return -ENOSYS;  
    23.   
    24.     num_registered_fb++;        /*对注册的FB计数*/  
    25.     /*寻找第一个空位*/  
    26.     for (i = 0 ; i < FB_MAX; i++)/*FB_MAX=32,也就是最多32个framebuffer*/  
    27.         if (!registered_fb[i])  /*struct fb_info *registered_fb[FB_MAX]*/  
    28.             break;  
    29.     fb_info->node = i;  
    30.     mutex_init(&fb_info->lock);  /*初始化互斥体*/  
    31.   
    32.     fb_info->dev = device_create(fb_class, fb_info->device,/*创建设备节点,节点名为fbx*/  
    33.                      MKDEV(FB_MAJOR, i), NULL, "fb%d", i);  
    34.     if (IS_ERR(fb_info->dev)) {  
    35.         /* Not fatal */  
    36.         printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld ", i, PTR_ERR(fb_info->dev));  
    37.         fb_info->dev = NULL;  
    38.     } else  
    39.         fb_init_device(fb_info);    /*初始化,在class/graphics/fbx/下创建设备属性*/  
    40.   
    41.     if (fb_info->pixmap.addr == NULL) {  
    42.         fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);/*分配内存,1024 * 8字节*/  
    43.         if (fb_info->pixmap.addr) {  
    44.             fb_info->pixmap.size = FBPIXMAPSIZE;  
    45.             fb_info->pixmap.buf_align = 1;  
    46.             fb_info->pixmap.scan_align = 1;  
    47.             fb_info->pixmap.access_align = 32;  
    48.             fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;  
    49.         }  
    50.     }     
    51.     fb_info->pixmap.offset = 0;  
    52.   
    53.     if (!fb_info->pixmap.blit_x)  
    54.         fb_info->pixmap.blit_x = ~(u32)0;  
    55.   
    56.     if (!fb_info->pixmap.blit_y)  
    57.         fb_info->pixmap.blit_y = ~(u32)0;  
    58.   
    59.     if (!fb_info->modelist.prev || !fb_info->modelist.next)   /*该链表没有指向其他节点*/  
    60.         INIT_LIST_HEAD(&fb_info->modelist);  /*初始化链表头*/  
    61.   
    62.     fb_var_to_videomode(&mode, &fb_info->var);/*转换fb_var_screeninfo成fb_videomode*/  
    63.     fb_add_videomode(&mode, &fb_info->modelist);/*添加mode至链表中*/  
    64.     registered_fb[i] = fb_info;  
    65.   
    66.     event.info = fb_info;  
    67.     if (!lock_fb_info(fb_info))  
    68.         return -ENODEV;  
    69.     fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);/*???*/  
    70.     unlock_fb_info(fb_info);  
    71.     return 0;  
    72. }  


    从这个函数我们可以看出,framebuffer子系统只支持32个设备。在创建了设备节点以后,建立设备属性节点,随后将fb_var_screeninfo转换成fb_videomode,最后添加fb_videomode至链表中。

    我们看下其中调用的函数,首先是fb_init_device。

    下列代码位于drivers/video/fbsysfs.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. int fb_init_device(struct fb_info *fb_info)  
    2. {  
    3.     int i, error = 0;  
    4.   
    5.     dev_set_drvdata(fb_info->dev, fb_info);  
    6.   
    7.     fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;  
    8.   
    9.     /*建立设备属性*/  
    10.     for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {  
    11.         error = device_create_file(fb_info->dev, &device_attrs[i]);  
    12.   
    13.         if (error)  
    14.             break;  
    15.     }  
    16.   
    17.     if (error) {  
    18.         while (--i >= 0)  
    19.             device_remove_file(fb_info->dev, &device_attrs[i]);  
    20.         fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;  
    21.     }  
    22.   
    23.     return 0;  
    24. }  
    25.   
    26. /* When cmap is added back in it should be a binary attribute 
    27.  * not a text one. Consideration should also be given to converting 
    28.  * fbdev to use configfs instead of sysfs */  
    29. static struct device_attribute device_attrs[] = {  
    30.     __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),  
    31.     __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),  
    32.     __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),  
    33.     __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),  
    34.     __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),  
    35.     __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),  
    36.     __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),  
    37.     __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),  
    38.     __ATTR(name, S_IRUGO, show_name, NULL),  
    39.     __ATTR(stride, S_IRUGO, show_stride, NULL),  
    40.     __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),  
    41.     __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),  
    42. #ifdef CONFIG_FB_BACKLIGHT   
    43.     __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),  
    44. #endif   
    45. };  
    [cpp] view plain copy
     
    1. int fb_init_device(struct fb_info *fb_info)  
    2. {  
    3.     int i, error = 0;  
    4.   
    5.     dev_set_drvdata(fb_info->dev, fb_info);  
    6.   
    7.     fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;  
    8.   
    9.     /*建立设备属性*/  
    10.     for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {  
    11.         error = device_create_file(fb_info->dev, &device_attrs[i]);  
    12.   
    13.         if (error)  
    14.             break;  
    15.     }  
    16.   
    17.     if (error) {  
    18.         while (--i >= 0)  
    19.             device_remove_file(fb_info->dev, &device_attrs[i]);  
    20.         fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;  
    21.     }  
    22.   
    23.     return 0;  
    24. }  
    25.   
    26. /* When cmap is added back in it should be a binary attribute 
    27.  * not a text one. Consideration should also be given to converting 
    28.  * fbdev to use configfs instead of sysfs */  
    29. static struct device_attribute device_attrs[] = {  
    30.     __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),  
    31.     __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),  
    32.     __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),  
    33.     __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),  
    34.     __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),  
    35.     __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),  
    36.     __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),  
    37.     __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),  
    38.     __ATTR(name, S_IRUGO, show_name, NULL),  
    39.     __ATTR(stride, S_IRUGO, show_stride, NULL),  
    40.     __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),  
    41.     __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),  
    42. #ifdef CONFIG_FB_BACKLIGHT  
    43.     __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),  
    44. #endif  
    45. };  


    我们可以在/sys/class/graphics/fb0下发现这些属性文件。

    [root@yj423 fb0]#pwd
    /sys/class/graphics/fb0
    [root@yj423 fb0]#ls
    bits_per_pixel  cursor          mode            pan             state           uevent
    blank           dev             modes           power           stride          virtual_size
    console         device          name            rotate          subsystem


    接着看下fb_var_to_videomode和fb_add_videomode函数。

    下列代码位于drivers/video/modedb.c和drivers/video/fb.h

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct fb_videomode {  
    2.     const char *name;   /* optional */  
    3.     u32 refresh;        /* optional */  
    4.     u32 xres;  
    5.     u32 yres;  
    6.     u32 pixclock;  
    7.     u32 left_margin;  
    8.     u32 right_margin;  
    9.     u32 upper_margin;  
    10.     u32 lower_margin;  
    11.     u32 hsync_len;  
    12.     u32 vsync_len;  
    13.     u32 sync;  
    14.     u32 vmode;  
    15.     u32 flag;  
    16. };  
    17.   
    18. /** 
    19.  * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode 
    20.  * @mode: pointer to struct fb_videomode 
    21.  * @var: pointer to struct fb_var_screeninfo 
    22.  */  
    23. void fb_var_to_videomode(struct fb_videomode *mode,  
    24.              const struct fb_var_screeninfo *var)  
    25. {  
    26.     u32 pixclock, hfreq, htotal, vtotal;  
    27.   
    28.     mode->name = NULL;  
    29.     mode->xres = var->xres;  
    30.     mode->yres = var->yres;  
    31.     mode->pixclock = var->pixclock;  
    32.     mode->hsync_len = var->hsync_len;  
    33.     mode->vsync_len = var->vsync_len;  
    34.     mode->left_margin = var->left_margin;  
    35.     mode->right_margin = var->right_margin;  
    36.     mode->upper_margin = var->upper_margin;  
    37.     mode->lower_margin = var->lower_margin;  
    38.     mode->sync = var->sync;  
    39.     mode->vmode = var->vmode & FB_VMODE_MASK;  
    40.     mode->flag = FB_MODE_IS_FROM_VAR;  
    41.     mode->refresh = 0;  
    42.   
    43.     if (!var->pixclock)  
    44.         return;  
    45.   
    46.     pixclock = PICOS2KHZ(var->pixclock) * 1000;  
    47.   
    48.     htotal = var->xres + var->right_margin + var->hsync_len +  
    49.         var->left_margin;  
    50.     vtotal = var->yres + var->lower_margin + var->vsync_len +  
    51.         var->upper_margin;  
    52.   
    53.     if (var->vmode & FB_VMODE_INTERLACED)  
    54.         vtotal /= 2;  
    55.     if (var->vmode & FB_VMODE_DOUBLE)  
    56.         vtotal *= 2;  
    57.   
    58.     hfreq = pixclock/htotal;  
    59.     mode->refresh = hfreq/vtotal;  
    60. }  
    61.   
    62. /** 
    63.  * fb_add_videomode: adds videomode entry to modelist 
    64.  * @mode: videomode to add 
    65.  * @head: struct list_head of modelist 
    66.  * 
    67.  * NOTES: 
    68.  * Will only add unmatched mode entries 
    69.  */  
    70. int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)  
    71. {  
    72.     struct list_head *pos;  
    73.     struct fb_modelist *modelist;d  
    74.     struct fb_videomode *m;  
    75.     int found = 0;  
    76.     /*遍历所有的fb_modelist,查找mode是否存在*/  
    77.     list_for_each(pos, head) {  
    78.         modelist = list_entry(pos, struct fb_modelist, list);  
    79.         m = &modelist->mode;  
    80.         if (fb_mode_is_equal(m, mode)) {    /*比较两个fb_videomode*/  
    81.             found = 1;                        /*该fb_videomode已存在*/  
    82.             break;  
    83.         }  
    84.     }  
    85.     if (!found) {    /*不存在*/  
    86.         modelist = kmalloc(sizeof(struct fb_modelist),    /*分配fb_modelist*/  
    87.                           GFP_KERNEL);  
    88.   
    89.         if (!modelist)  
    90.             return -ENOMEM;  
    91.         modelist->mode = *mode;            /*保存mode*/  
    92.         list_add(&modelist->list, head);/*添加mode至链表中*/  
    93.     }  
    94.     return 0;  
    95. }  
    96.   
    97. /** 
    98.  * fb_mode_is_equal - compare 2 videomodes 
    99.  * @mode1: first videomode 
    100.  * @mode2: second videomode 
    101.  * 
    102.  * RETURNS: 
    103.  * 1 if equal, 0 if not 
    104.  */  
    105. int fb_mode_is_equal(const struct fb_videomode *mode1,  
    106.              const struct fb_videomode *mode2)  
    107. {  
    108.     return (mode1->xres         == mode2->xres &&  
    109.         mode1->yres         == mode2->yres &&  
    110.         mode1->pixclock     == mode2->pixclock &&  
    111.         mode1->hsync_len    == mode2->hsync_len &&  
    112.         mode1->vsync_len    == mode2->vsync_len &&  
    113.         mode1->left_margin  == mode2->left_margin &&  
    114.         mode1->right_margin == mode2->right_margin &&  
    115.         mode1->upper_margin == mode2->upper_margin &&  
    116.         mode1->lower_margin == mode2->lower_margin &&  
    117.         mode1->sync         == mode2->sync &&  
    118.         mode1->vmode        == mode2->vmode);  
    119. }  
    [cpp] view plain copy
     
    1. struct fb_videomode {  
    2.     const char *name;   /* optional */  
    3.     u32 refresh;        /* optional */  
    4.     u32 xres;  
    5.     u32 yres;  
    6.     u32 pixclock;  
    7.     u32 left_margin;  
    8.     u32 right_margin;  
    9.     u32 upper_margin;  
    10.     u32 lower_margin;  
    11.     u32 hsync_len;  
    12.     u32 vsync_len;  
    13.     u32 sync;  
    14.     u32 vmode;  
    15.     u32 flag;  
    16. };  
    17.   
    18. /** 
    19.  * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode 
    20.  * @mode: pointer to struct fb_videomode 
    21.  * @var: pointer to struct fb_var_screeninfo 
    22.  */  
    23. void fb_var_to_videomode(struct fb_videomode *mode,  
    24.              const struct fb_var_screeninfo *var)  
    25. {  
    26.     u32 pixclock, hfreq, htotal, vtotal;  
    27.   
    28.     mode->name = NULL;  
    29.     mode->xres = var->xres;  
    30.     mode->yres = var->yres;  
    31.     mode->pixclock = var->pixclock;  
    32.     mode->hsync_len = var->hsync_len;  
    33.     mode->vsync_len = var->vsync_len;  
    34.     mode->left_margin = var->left_margin;  
    35.     mode->right_margin = var->right_margin;  
    36.     mode->upper_margin = var->upper_margin;  
    37.     mode->lower_margin = var->lower_margin;  
    38.     mode->sync = var->sync;  
    39.     mode->vmode = var->vmode & FB_VMODE_MASK;  
    40.     mode->flag = FB_MODE_IS_FROM_VAR;  
    41.     mode->refresh = 0;  
    42.   
    43.     if (!var->pixclock)  
    44.         return;  
    45.   
    46.     pixclock = PICOS2KHZ(var->pixclock) * 1000;  
    47.   
    48.     htotal = var->xres + var->right_margin + var->hsync_len +  
    49.         var->left_margin;  
    50.     vtotal = var->yres + var->lower_margin + var->vsync_len +  
    51.         var->upper_margin;  
    52.   
    53.     if (var->vmode & FB_VMODE_INTERLACED)  
    54.         vtotal /= 2;  
    55.     if (var->vmode & FB_VMODE_DOUBLE)  
    56.         vtotal *= 2;  
    57.   
    58.     hfreq = pixclock/htotal;  
    59.     mode->refresh = hfreq/vtotal;  
    60. }  
    61.   
    62. /** 
    63.  * fb_add_videomode: adds videomode entry to modelist 
    64.  * @mode: videomode to add 
    65.  * @head: struct list_head of modelist 
    66.  * 
    67.  * NOTES: 
    68.  * Will only add unmatched mode entries 
    69.  */  
    70. int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)  
    71. {  
    72.     struct list_head *pos;  
    73.     struct fb_modelist *modelist;d  
    74.     struct fb_videomode *m;  
    75.     int found = 0;  
    76.     /*遍历所有的fb_modelist,查找mode是否存在*/  
    77.     list_for_each(pos, head) {  
    78.         modelist = list_entry(pos, struct fb_modelist, list);  
    79.         m = &modelist->mode;  
    80.         if (fb_mode_is_equal(m, mode)) {    /*比较两个fb_videomode*/  
    81.             found = 1;                        /*该fb_videomode已存在*/  
    82.             break;  
    83.         }  
    84.     }  
    85.     if (!found) {    /*不存在*/  
    86.         modelist = kmalloc(sizeof(struct fb_modelist),    /*分配fb_modelist*/  
    87.                           GFP_KERNEL);  
    88.   
    89.         if (!modelist)  
    90.             return -ENOMEM;  
    91.         modelist->mode = *mode;            /*保存mode*/  
    92.         list_add(&modelist->list, head);/*添加mode至链表中*/  
    93.     }  
    94.     return 0;  
    95. }  
    96.   
    97. /** 
    98.  * fb_mode_is_equal - compare 2 videomodes 
    99.  * @mode1: first videomode 
    100.  * @mode2: second videomode 
    101.  * 
    102.  * RETURNS: 
    103.  * 1 if equal, 0 if not 
    104.  */  
    105. int fb_mode_is_equal(const struct fb_videomode *mode1,  
    106.              const struct fb_videomode *mode2)  
    107. {  
    108.     return (mode1->xres         == mode2->xres &&  
    109.         mode1->yres         == mode2->yres &&  
    110.         mode1->pixclock     == mode2->pixclock &&  
    111.         mode1->hsync_len    == mode2->hsync_len &&  
    112.         mode1->vsync_len    == mode2->vsync_len &&  
    113.         mode1->left_margin  == mode2->left_margin &&  
    114.         mode1->right_margin == mode2->right_margin &&  
    115.         mode1->upper_margin == mode2->upper_margin &&  
    116.         mode1->lower_margin == mode2->lower_margin &&  
    117.         mode1->sync         == mode2->sync &&  
    118.         mode1->vmode        == mode2->vmode);  
    119. }  


    fb_var_to_videomode函数只是将fb_var_screeninfo结构转换成fb_videomode结构。而fb_add_videomode函数查找是否该fb_videomode已经存在,如果不存在则添加到列表中。

    3.4 字符设备方法

      在看过framebuffer子系统建立和注册过程后,我们看下framebuffer留给用户空间的API是怎样实现的。

    本小结只分析5个常用的方法,即open,release,read,write和ioctl。

      因为所有的方法和struct fb_ops定义的方法有紧密的联系,而该结构的定义由驱动程序给出,在这里我们提前看下在驱动中是如何定义的。

     下列代码位于drivers/video/s3c2410fb..c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static struct fb_ops s3c2410fb_ops = {  
    2.     .owner      = THIS_MODULE,  
    3.     .fb_check_var   = s3c2410fb_check_var,              /*检查变量的合法性*/  
    4.     .fb_set_par = s3c2410fb_set_par,            /*将参数写入LCD控制器,该函数由帧缓冲核心调用*/  
    5.     .fb_blank   = s3c2410fb_blank,          /*该方法支持显示消隐和去消隐*/  
    6.     .fb_setcolreg   = s3c2410fb_setcolreg,                  /*设置颜色寄存器*/  
    7.     .fb_fillrect    = cfb_fillrect,             /*用像素行填充矩形框,通用库函数*/  
    8.     .fb_copyarea    = cfb_copyarea,             /*将屏幕的一个矩形区域复制到另一个区域,通用库函数*/  
    9.     .fb_imageblit   = cfb_imageblit,            /*显示一副图像,通用库函数*/  
    10. };  
    [cpp] view plain copy
     
    1. static struct fb_ops s3c2410fb_ops = {  
    2.     .owner      = THIS_MODULE,  
    3.     .fb_check_var   = s3c2410fb_check_var,              /*检查变量的合法性*/  
    4.     .fb_set_par = s3c2410fb_set_par,            /*将参数写入LCD控制器,该函数由帧缓冲核心调用*/  
    5.     .fb_blank   = s3c2410fb_blank,          /*该方法支持显示消隐和去消隐*/  
    6.     .fb_setcolreg   = s3c2410fb_setcolreg,                  /*设置颜色寄存器*/  
    7.     .fb_fillrect    = cfb_fillrect,             /*用像素行填充矩形框,通用库函数*/  
    8.     .fb_copyarea    = cfb_copyarea,             /*将屏幕的一个矩形区域复制到另一个区域,通用库函数*/  
    9.     .fb_imageblit   = cfb_imageblit,            /*显示一副图像,通用库函数*/  
    10. };  

    最下面的三个方法使用的是内核提供的库函数,而上面4个则是由驱动提供。

    3.4.1 open方法

    下列代码位于drivers/video/fbmem.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static int  
    2. fb_open(struct inode *inode, struct file *file)  
    3. __acquires(&info->lock)  
    4. __releases(&info->lock)  
    5. {  
    6.     int fbidx = iminor(inode);  
    7.     struct fb_info *info;  
    8.     int res = 0;  
    9.   
    10.     if (fbidx >= FB_MAX)  
    11.         return -ENODEV;  
    12.     info = registered_fb[fbidx];        /*在register_framebuffer函数中已经设置了元素*/  
    13.     if (!info)  
    14.         request_module("fb%d", fbidx);  /*加载模块,这里不加载*/  
    15.     info = registered_fb[fbidx];  
    16.     if (!info)  
    17.         return -ENODEV;  
    18.     mutex_lock(&info->lock);         /*加锁互斥体*/  
    19.     if (!try_module_get(info->fbops->owner)) {    /*增加模块引用计数*/  
    20.         res = -ENODEV;  
    21.         goto out;  
    22.     }  
    23.     file->private_data = info;       /*保存info*/  
    24.     if (info->fbops->fb_open) {       /*这里fb_open方法为空*/  
    25.         res = info->fbops->fb_open(info,1);  
    26.         if (res)  
    27.             module_put(info->fbops->owner);  
    28.     }  
    29. #ifdef CONFIG_FB_DEFERRED_IO   
    30.     if (info->fbdefio)  
    31.         fb_deferred_io_open(info, inode, file);  
    32. #endif   
    33. out:  
    34.     mutex_unlock(&info->lock);       /*解锁互斥体*/  
    35.     return res;  
    36. }  
    [cpp] view plain copy
     
    1. static int  
    2. fb_open(struct inode *inode, struct file *file)  
    3. __acquires(&info->lock)  
    4. __releases(&info->lock)  
    5. {  
    6.     int fbidx = iminor(inode);  
    7.     struct fb_info *info;  
    8.     int res = 0;  
    9.   
    10.     if (fbidx >= FB_MAX)  
    11.         return -ENODEV;  
    12.     info = registered_fb[fbidx];        /*在register_framebuffer函数中已经设置了元素*/  
    13.     if (!info)  
    14.         request_module("fb%d", fbidx);  /*加载模块,这里不加载*/  
    15.     info = registered_fb[fbidx];  
    16.     if (!info)  
    17.         return -ENODEV;  
    18.     mutex_lock(&info->lock);         /*加锁互斥体*/  
    19.     if (!try_module_get(info->fbops->owner)) {    /*增加模块引用计数*/  
    20.         res = -ENODEV;  
    21.         goto out;  
    22.     }  
    23.     file->private_data = info;       /*保存info*/  
    24.     if (info->fbops->fb_open) {       /*这里fb_open方法为空*/  
    25.         res = info->fbops->fb_open(info,1);  
    26.         if (res)  
    27.             module_put(info->fbops->owner);  
    28.     }  
    29. #ifdef CONFIG_FB_DEFERRED_IO  
    30.     if (info->fbdefio)  
    31.         fb_deferred_io_open(info, inode, file);  
    32. #endif  
    33. out:  
    34.     mutex_unlock(&info->lock);       /*解锁互斥体*/  
    35.     return res;  
    36. }  

    主要的一个工作就是增加模块引用计数。还有,程序会判断是否fb_open在驱动中给出,如果有则调用该方法。我们已经知道fb_open没有给出。

    3.4.2 release方法

    下列代码位于drivers/video/fbmem.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static int   
    2. fb_release(struct inode *inode, struct file *file)  
    3. __acquires(&info->lock)  
    4. __releases(&info->lock)  
    5. {  
    6.     struct fb_info * const info = file->private_data;  
    7.   
    8.     mutex_lock(&info->lock);  
    9.     if (info->fbops->fb_release)  /*这里fb_release为空*/  
    10.         info->fbops->fb_release(info,1);  
    11.     module_put(info->fbops->owner);   /*减少模块引用计数*/  
    12.     mutex_unlock(&info->lock);  
    13.     return 0;  
    14. }  
    [cpp] view plain copy
     
    1. static int   
    2. fb_release(struct inode *inode, struct file *file)  
    3. __acquires(&info->lock)  
    4. __releases(&info->lock)  
    5. {  
    6.     struct fb_info * const info = file->private_data;  
    7.   
    8.     mutex_lock(&info->lock);  
    9.     if (info->fbops->fb_release)  /*这里fb_release为空*/  
    10.         info->fbops->fb_release(info,1);  
    11.     module_put(info->fbops->owner);   /*减少模块引用计数*/  
    12.     mutex_unlock(&info->lock);  
    13.     return 0;  
    14. }  

    和open相反,减少模块引用计数。

    3.4.3 write方法

      通过调用该方法,LCD将显示画面。

      下列代码位于drivers/video/fbmem.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static ssize_t  
    2. fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)  
    3. {  
    4.     unsigned long p = *ppos;  
    5.     struct inode *inode = file->f_path.dentry->d_inode;  
    6.     int fbidx = iminor(inode);  
    7.     struct fb_info *info = registered_fb[fbidx];  
    8.     u32 *buffer, *src;  
    9.     u32 __iomem *dst;  
    10.     int c, i, cnt = 0, err = 0;  
    11.     unsigned long total_size;  
    12.   
    13.     if (!info || !info->screen_base)    /*screen_base在驱动中给出*/  
    14.         return -ENODEV;  
    15.   
    16.     if (info->state != FBINFO_STATE_RUNNING)  
    17.         return -EPERM;  
    18.   
    19.     if (info->fbops->fb_write)    /*没有fb_write方法*/  
    20.         return info->fbops->fb_write(info, buf, count, ppos);  
    21.       
    22.     total_size = info->screen_size;    /*screen_size没有给出*/  
    23.   
    24.     if (total_size == 0)  
    25.         total_size = info->fix.smem_len;/*153600字节,驱动probe方法中计算*/  
    26.   
    27.     if (p > total_size)  
    28.         return -EFBIG;  
    29.   
    30.     if (count > total_size) {    /*要写入的字节数大于153600*/  
    31.         err = -EFBIG;        /*file too big*/  
    32.         count = total_size;  
    33.     }  
    34.   
    35.     if (count + p > total_size) {/*偏移量加上字节数超出了缓冲区*/  
    36.         if (!err)  
    37.             err = -ENOSPC;  
    38.   
    39.         count = total_size - p;  
    40.     }  
    41.   
    42.     /*分配buffer,GFP_KERNEL*/  
    43.     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,  
    44.              GFP_KERNEL);                /  
    45.     if (!buffer)  
    46.         return -ENOMEM;  
    47.   
    48.     dst = (u32 __iomem *) (info->screen_base + p);/*修改目的指针*/  
    49.   
    50.     if (info->fbops->fb_sync)    /*没有定义fb_sync*/  
    51.         info->fbops->fb_sync(info);  
    52.   
    53.     while (count) {  
    54.         c = (count > PAGE_SIZE) ? PAGE_SIZE : count;  
    55.         src = buffer;  
    56.   
    57.         /*从buf(用户空间)拷贝数据到src中,一开始为1页,最后为count字节*/  
    58.         if (copy_from_user(src, buf, c)) {      
    59.             err = -EFAULT;  
    60.             break;  
    61.         }  
    62.         /*一次for循环,写入4个字节数据到dst处*/  
    63.         for (i = c >> 2; i--; )  
    64.             fb_writel(*src++, dst++);  
    65.         /*最后还有3个,2个或者1个字节*/  
    66.         if (c & 3) {  
    67.             u8 *src8 = (u8 *) src;  
    68.             u8 __iomem *dst8 = (u8 __iomem *) dst;  
    69.             /*一次写入一个字节*/  
    70.             for (i = c & 3; i--; )  
    71.                 fb_writeb(*src8++, dst8++);  
    72.   
    73.             dst = (u32 __iomem *) dst8;  
    74.         }  
    75.   
    76.         *ppos += c;    /*用户空间偏移量增加*/  
    77.         buf += c;    /*用户空间指针增加*/  
    78.         cnt += c;    /*修改已发送字节数*/  
    79.         count -= c;    /*减去1页*/  
    80.     }  
    81.   
    82.     kfree(buffer);    /*释放buffer*/  
    83.   
    84.     return (cnt) ? cnt : err;  
    85. }  
    [cpp] view plain copy
     
    1. static ssize_t  
    2. fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)  
    3. {  
    4.     unsigned long p = *ppos;  
    5.     struct inode *inode = file->f_path.dentry->d_inode;  
    6.     int fbidx = iminor(inode);  
    7.     struct fb_info *info = registered_fb[fbidx];  
    8.     u32 *buffer, *src;  
    9.     u32 __iomem *dst;  
    10.     int c, i, cnt = 0, err = 0;  
    11.     unsigned long total_size;  
    12.   
    13.     if (!info || !info->screen_base)    /*screen_base在驱动中给出*/  
    14.         return -ENODEV;  
    15.   
    16.     if (info->state != FBINFO_STATE_RUNNING)  
    17.         return -EPERM;  
    18.   
    19.     if (info->fbops->fb_write)    /*没有fb_write方法*/  
    20.         return info->fbops->fb_write(info, buf, count, ppos);  
    21.       
    22.     total_size = info->screen_size;    /*screen_size没有给出*/  
    23.   
    24.     if (total_size == 0)  
    25.         total_size = info->fix.smem_len;/*153600字节,驱动probe方法中计算*/  
    26.   
    27.     if (p > total_size)  
    28.         return -EFBIG;  
    29.   
    30.     if (count > total_size) {    /*要写入的字节数大于153600*/  
    31.         err = -EFBIG;        /*file too big*/  
    32.         count = total_size;  
    33.     }  
    34.   
    35.     if (count + p > total_size) {/*偏移量加上字节数超出了缓冲区*/  
    36.         if (!err)  
    37.             err = -ENOSPC;  
    38.   
    39.         count = total_size - p;  
    40.     }  
    41.   
    42.     /*分配buffer,GFP_KERNEL*/  
    43.     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,  
    44.              GFP_KERNEL);                /  
    45.     if (!buffer)  
    46.         return -ENOMEM;  
    47.   
    48.     dst = (u32 __iomem *) (info->screen_base + p);/*修改目的指针*/  
    49.   
    50.     if (info->fbops->fb_sync)    /*没有定义fb_sync*/  
    51.         info->fbops->fb_sync(info);  
    52.   
    53.     while (count) {  
    54.         c = (count > PAGE_SIZE) ? PAGE_SIZE : count;  
    55.         src = buffer;  
    56.   
    57.         /*从buf(用户空间)拷贝数据到src中,一开始为1页,最后为count字节*/  
    58.         if (copy_from_user(src, buf, c)) {      
    59.             err = -EFAULT;  
    60.             break;  
    61.         }  
    62.         /*一次for循环,写入4个字节数据到dst处*/  
    63.         for (i = c >> 2; i--; )  
    64.             fb_writel(*src++, dst++);  
    65.         /*最后还有3个,2个或者1个字节*/  
    66.         if (c & 3) {  
    67.             u8 *src8 = (u8 *) src;  
    68.             u8 __iomem *dst8 = (u8 __iomem *) dst;  
    69.             /*一次写入一个字节*/  
    70.             for (i = c & 3; i--; )  
    71.                 fb_writeb(*src8++, dst8++);  
    72.   
    73.             dst = (u32 __iomem *) dst8;  
    74.         }  
    75.   
    76.         *ppos += c;    /*用户空间偏移量增加*/  
    77.         buf += c;    /*用户空间指针增加*/  
    78.         cnt += c;    /*修改已发送字节数*/  
    79.         count -= c;    /*减去1页*/  
    80.     }  
    81.   
    82.     kfree(buffer);    /*释放buffer*/  
    83.   
    84.     return (cnt) ? cnt : err;  
    85. }  


    这里,做了一系列的检查之后,开始拷贝数据。这里一个有三个buffer,一个是用户空间提供的buf,一个是在这里新开辟的buffer,还有就是驱动层提供的screen_base。

    数据流如下:
     

    用户空间的数据首先被复制到buffer中,然后从buffer中复制到screen_base中,最后被映射到LCD上,LCD就显示响应的画面了。

    3.4.4 read方法

    该方法用于读取屏幕画面的数据。

    read和write类似,只是数据流是反响的,就不多做介绍了。

    下列代码位于drivers/video/fbmem.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static ssize_t  
    2. fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  
    3. {  
    4.     unsigned long p = *ppos;  
    5.     struct inode *inode = file->f_path.dentry->d_inode;  
    6.     int fbidx = iminor(inode);  
    7.     struct fb_info *info = registered_fb[fbidx];  
    8.     u32 *buffer, *dst;  
    9.     u32 __iomem *src;  
    10.     int c, i, cnt = 0, err = 0;  
    11.     unsigned long total_size;  
    12.   
    13.     if (!info || ! info->screen_base)  
    14.         return -ENODEV;  
    15.   
    16.     if (info->state != FBINFO_STATE_RUNNING)  
    17.         return -EPERM;  
    18.   
    19.     if (info->fbops->fb_read) /*没有定义fb_read*/  
    20.         return info->fbops->fb_read(info, buf, count, ppos);  
    21.       
    22.     total_size = info->screen_size;  
    23.   
    24.     if (total_size == 0)  
    25.         total_size = info->fix.smem_len;  
    26.   
    27.     if (p >= total_size)  
    28.         return 0;  
    29.   
    30.     if (count >= total_size)  
    31.         count = total_size;  
    32.   
    33.     if (count + p > total_size)  
    34.         count = total_size - p;  
    35.   
    36.     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,  
    37.              GFP_KERNEL);  
    38.     if (!buffer)  
    39.         return -ENOMEM;  
    40.   
    41.     src = (u32 __iomem *) (info->screen_base + p);  
    42.   
    43.     if (info->fbops->fb_sync)  
    44.         info->fbops->fb_sync(info);/*没有定义fb_sync*/  
    45.   
    46.     while (count) {  
    47.         c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;  
    48.         dst = buffer;  
    49.         for (i = c >> 2; i--; )  
    50.             *dst++ = fb_readl(src++);  
    51.         if (c & 3) {  
    52.             u8 *dst8 = (u8 *) dst;  
    53.             u8 __iomem *src8 = (u8 __iomem *) src;  
    54.   
    55.             for (i = c & 3; i--;)  
    56.                 *dst8++ = fb_readb(src8++);  
    57.   
    58.             src = (u32 __iomem *) src8;  
    59.         }  
    60.   
    61.         if (copy_to_user(buf, buffer, c)) {  
    62.             err = -EFAULT;  
    63.             break;  
    64.         }  
    65.         *ppos += c;  
    66.         buf += c;  
    67.         cnt += c;  
    68.         count -= c;  
    69.     }  
    70.   
    71.     kfree(buffer);  
    72.   
    73.     return (err) ? err : cnt;  
    74. }  
    [cpp] view plain copy
     
    1. static ssize_t  
    2. fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  
    3. {  
    4.     unsigned long p = *ppos;  
    5.     struct inode *inode = file->f_path.dentry->d_inode;  
    6.     int fbidx = iminor(inode);  
    7.     struct fb_info *info = registered_fb[fbidx];  
    8.     u32 *buffer, *dst;  
    9.     u32 __iomem *src;  
    10.     int c, i, cnt = 0, err = 0;  
    11.     unsigned long total_size;  
    12.   
    13.     if (!info || ! info->screen_base)  
    14.         return -ENODEV;  
    15.   
    16.     if (info->state != FBINFO_STATE_RUNNING)  
    17.         return -EPERM;  
    18.   
    19.     if (info->fbops->fb_read) /*没有定义fb_read*/  
    20.         return info->fbops->fb_read(info, buf, count, ppos);  
    21.       
    22.     total_size = info->screen_size;  
    23.   
    24.     if (total_size == 0)  
    25.         total_size = info->fix.smem_len;  
    26.   
    27.     if (p >= total_size)  
    28.         return 0;  
    29.   
    30.     if (count >= total_size)  
    31.         count = total_size;  
    32.   
    33.     if (count + p > total_size)  
    34.         count = total_size - p;  
    35.   
    36.     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,  
    37.              GFP_KERNEL);  
    38.     if (!buffer)  
    39.         return -ENOMEM;  
    40.   
    41.     src = (u32 __iomem *) (info->screen_base + p);  
    42.   
    43.     if (info->fbops->fb_sync)  
    44.         info->fbops->fb_sync(info);/*没有定义fb_sync*/  
    45.   
    46.     while (count) {  
    47.         c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;  
    48.         dst = buffer;  
    49.         for (i = c >> 2; i--; )  
    50.             *dst++ = fb_readl(src++);  
    51.         if (c & 3) {  
    52.             u8 *dst8 = (u8 *) dst;  
    53.             u8 __iomem *src8 = (u8 __iomem *) src;  
    54.   
    55.             for (i = c & 3; i--;)  
    56.                 *dst8++ = fb_readb(src8++);  
    57.   
    58.             src = (u32 __iomem *) src8;  
    59.         }  
    60.   
    61.         if (copy_to_user(buf, buffer, c)) {  
    62.             err = -EFAULT;  
    63.             break;  
    64.         }  
    65.         *ppos += c;  
    66.         buf += c;  
    67.         cnt += c;  
    68.         count -= c;  
    69.     }  
    70.   
    71.     kfree(buffer);  
    72.   
    73.     return (err) ? err : cnt;  
    74. }  

    3.4.5 ioctl方法

    这里只是简单的看下ioctl方法,这个函数调用很多其他的函数,详细的请自己看吧。

    下列代码位于drivers/video/fbmem.c

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
    2. {  
    3.     /*获取inode,再获取对应的fb_info*/  
    4.     struct inode *inode = file->f_path.dentry->d_inode;  
    5.     int fbidx = iminor(inode);    
    6.     struct fb_info *info = registered_fb[fbidx];  
    7.   
    8.     return do_fb_ioctl(info, cmd, arg);  
    9. }  
    10.   
    11. static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,  
    12.             unsigned long arg)  
    13. {  
    14.     struct fb_ops *fb;  
    15.     struct fb_var_screeninfo var;  
    16.     struct fb_fix_screeninfo fix;  
    17.     struct fb_con2fbmap con2fb;  
    18.     struct fb_cmap cmap_from;  
    19.     struct fb_cmap_user cmap;  
    20.     struct fb_event event;  
    21.     void __user *argp = (void __user *)arg;  
    22.     long ret = 0;  
    23.   
    24.     switch (cmd) {  
    25.     /*获取fb_var_screeninfo*/  
    26.     case FBIOGET_VSCREENINFO:      
    27.         if (!lock_fb_info(info))    /*加锁互斥体info->lock*/  
    28.             return -ENODEV;  
    29.         var = info->var;            /*复制var*/  
    30.         unlock_fb_info(info);  
    31.   
    32.         ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;    /*复制var到用户空间*/  
    33.         break;  
    34.     /*设置fb_var_screeninfo*/  
    35.     case FBIOPUT_VSCREENINFO:  
    36.         if (copy_from_user(&var, argp, sizeof(var)))    /*从用户空间获取var*/  
    37.             return -EFAULT;  
    38.         if (!lock_fb_info(info))  
    39.             return -ENODEV;  
    40.         acquire_console_sem();  
    41.         info->flags |= FBINFO_MISC_USEREVENT;  
    42.         ret = fb_set_var(info, &var);            /*设置var*/  
    43.         info->flags &= ~FBINFO_MISC_USEREVENT;  
    44.         release_console_sem();  
    45.         unlock_fb_info(info);  
    46.         if (!ret && copy_to_user(argp, &var, sizeof(var)))  
    47.             ret = -EFAULT;  
    48.         break;  
    49.     /*获取fb_fix_screeninfo*/    /*fix为不可改变信息,只能获取,不能设置*/  
    50.     case FBIOGET_FSCREENINFO:  
    51.         if (!lock_fb_info(info))  
    52.             return -ENODEV;  
    53.         fix = info->fix;  
    54.         unlock_fb_info(info);  
    55.   
    56.         ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;  
    57.         break;  
    58.     /*设置fb_cmap*/      
    59.     case FBIOPUTCMAP:  
    60.         if (copy_from_user(&cmap, argp, sizeof(cmap)))  
    61.             return -EFAULT;  
    62.         ret = fb_set_user_cmap(&cmap, info);    /*设置fb_cmap*/  
    63.         break;  
    64.     /*获取fb_cmap*/      
    65.     case FBIOGETCMAP:  
    66.         if (copy_from_user(&cmap, argp, sizeof(cmap)))  
    67.             return -EFAULT;  
    68.         if (!lock_fb_info(info))  
    69.             return -ENODEV;  
    70.         cmap_from = info->cmap;  
    71.         unlock_fb_info(info);  
    72.         ret = fb_cmap_to_user(&cmap_from, &cmap);/*获取fb_cmp*/  
    73.         break;  
    74.     case FBIOPAN_DISPLAY:  
    75.         if (copy_from_user(&var, argp, sizeof(var)))  
    76.             return -EFAULT;  
    77.         if (!lock_fb_info(info))  
    78.             return -ENODEV;  
    79.         acquire_console_sem();  
    80.         ret = fb_pan_display(info, &var);  
    81.         release_console_sem();  
    82.         unlock_fb_info(info);  
    83.         if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))  
    84.             return -EFAULT;  
    85.         break;  
    86.     case FBIO_CURSOR:  
    87.         ret = -EINVAL;  
    88.         break;  
    89.     case FBIOGET_CON2FBMAP:  
    90.         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))  
    91.             return -EFAULT;  
    92.         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)  
    93.             return -EINVAL;  
    94.         con2fb.framebuffer = -1;  
    95.         event.data = &con2fb;  
    96.         if (!lock_fb_info(info))  
    97.             return -ENODEV;  
    98.         event.info = info;  
    99.         fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);  
    100.         unlock_fb_info(info);  
    101.         ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;  
    102.         break;  
    103.     case FBIOPUT_CON2FBMAP:  
    104.         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))  
    105.             return -EFAULT;  
    106.         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)  
    107.             return -EINVAL;  
    108.         if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)  
    109.             return -EINVAL;  
    110.         if (!registered_fb[con2fb.framebuffer])  
    111.             request_module("fb%d", con2fb.framebuffer);  
    112.         if (!registered_fb[con2fb.framebuffer]) {  
    113.             ret = -EINVAL;  
    114.             break;  
    115.         }  
    116.         event.data = &con2fb;  
    117.         if (!lock_fb_info(info))  
    118.             return -ENODEV;  
    119.         event.info = info;  
    120.         ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);  
    121.         unlock_fb_info(info);  
    122.         break;  
    123.     case FBIOBLANK:  
    124.         if (!lock_fb_info(info))  
    125.             return -ENODEV;  
    126.         acquire_console_sem();  
    127.         info->flags |= FBINFO_MISC_USEREVENT;  
    128.         ret = fb_blank(info, arg);        ?*最后调用驱动提供的s3c2410fb_blank*/  
    129.         info->flags &= ~FBINFO_MISC_USEREVENT;  
    130.         release_console_sem();  
    131.         unlock_fb_info(info);  
    132.         break;  
    133.     default:  
    134.         if (!lock_fb_info(info))  
    135.             return -ENODEV;  
    136.         fb = info->fbops;  
    137.         if (fb->fb_ioctl)        /*fb_ioctl为空*/  
    138.             ret = fb->fb_ioctl(info, cmd, arg);  
    139.         else  
    140.             ret = -ENOTTY;  
    141.         unlock_fb_info(info);  
    142.     }  
    143.     return ret;  
    144. }  
    [cpp] view plain copy
     
    1. static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
    2. {  
    3.     /*获取inode,再获取对应的fb_info*/  
    4.     struct inode *inode = file->f_path.dentry->d_inode;  
    5.     int fbidx = iminor(inode);    
    6.     struct fb_info *info = registered_fb[fbidx];  
    7.   
    8.     return do_fb_ioctl(info, cmd, arg);  
    9. }  
    10.   
    11. static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,  
    12.             unsigned long arg)  
    13. {  
    14.     struct fb_ops *fb;  
    15.     struct fb_var_screeninfo var;  
    16.     struct fb_fix_screeninfo fix;  
    17.     struct fb_con2fbmap con2fb;  
    18.     struct fb_cmap cmap_from;  
    19.     struct fb_cmap_user cmap;  
    20.     struct fb_event event;  
    21.     void __user *argp = (void __user *)arg;  
    22.     long ret = 0;  
    23.   
    24.     switch (cmd) {  
    25.     /*获取fb_var_screeninfo*/  
    26.     case FBIOGET_VSCREENINFO:      
    27.         if (!lock_fb_info(info))    /*加锁互斥体info->lock*/  
    28.             return -ENODEV;  
    29.         var = info->var;            /*复制var*/  
    30.         unlock_fb_info(info);  
    31.   
    32.         ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;    /*复制var到用户空间*/  
    33.         break;  
    34.     /*设置fb_var_screeninfo*/  
    35.     case FBIOPUT_VSCREENINFO:  
    36.         if (copy_from_user(&var, argp, sizeof(var)))    /*从用户空间获取var*/  
    37.             return -EFAULT;  
    38.         if (!lock_fb_info(info))  
    39.             return -ENODEV;  
    40.         acquire_console_sem();  
    41.         info->flags |= FBINFO_MISC_USEREVENT;  
    42.         ret = fb_set_var(info, &var);            /*设置var*/  
    43.         info->flags &= ~FBINFO_MISC_USEREVENT;  
    44.         release_console_sem();  
    45.         unlock_fb_info(info);  
    46.         if (!ret && copy_to_user(argp, &var, sizeof(var)))  
    47.             ret = -EFAULT;  
    48.         break;  
    49.     /*获取fb_fix_screeninfo*/    /*fix为不可改变信息,只能获取,不能设置*/  
    50.     case FBIOGET_FSCREENINFO:  
    51.         if (!lock_fb_info(info))  
    52.             return -ENODEV;  
    53.         fix = info->fix;  
    54.         unlock_fb_info(info);  
    55.   
    56.         ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;  
    57.         break;  
    58.     /*设置fb_cmap*/      
    59.     case FBIOPUTCMAP:  
    60.         if (copy_from_user(&cmap, argp, sizeof(cmap)))  
    61.             return -EFAULT;  
    62.         ret = fb_set_user_cmap(&cmap, info);    /*设置fb_cmap*/  
    63.         break;  
    64.     /*获取fb_cmap*/      
    65.     case FBIOGETCMAP:  
    66.         if (copy_from_user(&cmap, argp, sizeof(cmap)))  
    67.             return -EFAULT;  
    68.         if (!lock_fb_info(info))  
    69.             return -ENODEV;  
    70.         cmap_from = info->cmap;  
    71.         unlock_fb_info(info);  
    72.         ret = fb_cmap_to_user(&cmap_from, &cmap);/*获取fb_cmp*/  
    73.         break;  
    74.     case FBIOPAN_DISPLAY:  
    75.         if (copy_from_user(&var, argp, sizeof(var)))  
    76.             return -EFAULT;  
    77.         if (!lock_fb_info(info))  
    78.             return -ENODEV;  
    79.         acquire_console_sem();  
    80.         ret = fb_pan_display(info, &var);  
    81.         release_console_sem();  
    82.         unlock_fb_info(info);  
    83.         if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))  
    84.             return -EFAULT;  
    85.         break;  
    86.     case FBIO_CURSOR:  
    87.         ret = -EINVAL;  
    88.         break;  
    89.     case FBIOGET_CON2FBMAP:  
    90.         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))  
    91.             return -EFAULT;  
    92.         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)  
    93.             return -EINVAL;  
    94.         con2fb.framebuffer = -1;  
    95.         event.data = &con2fb;  
    96.         if (!lock_fb_info(info))  
    97.             return -ENODEV;  
    98.         event.info = info;  
    99.         fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);  
    100.         unlock_fb_info(info);  
    101.         ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;  
    102.         break;  
    103.     case FBIOPUT_CON2FBMAP:  
    104.         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))  
    105.             return -EFAULT;  
    106.         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)  
    107.             return -EINVAL;  
    108.         if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)  
    109.             return -EINVAL;  
    110.         if (!registered_fb[con2fb.framebuffer])  
    111.             request_module("fb%d", con2fb.framebuffer);  
    112.         if (!registered_fb[con2fb.framebuffer]) {  
    113.             ret = -EINVAL;  
    114.             break;  
    115.         }  
    116.         event.data = &con2fb;  
    117.         if (!lock_fb_info(info))  
    118.             return -ENODEV;  
    119.         event.info = info;  
    120.         ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);  
    121.         unlock_fb_info(info);  
    122.         break;  
    123.     case FBIOBLANK:  
    124.         if (!lock_fb_info(info))  
    125.             return -ENODEV;  
    126.         acquire_console_sem();  
    127.         info->flags |= FBINFO_MISC_USEREVENT;  
    128.         ret = fb_blank(info, arg);        ?*最后调用驱动提供的s3c2410fb_blank*/  
    129.         info->flags &= ~FBINFO_MISC_USEREVENT;  
    130.         release_console_sem();  
    131.         unlock_fb_info(info);  
    132.         break;  
    133.     default:  
    134.         if (!lock_fb_info(info))  
    135.             return -ENODEV;  
    136.         fb = info->fbops;  
    137.         if (fb->fb_ioctl)        /*fb_ioctl为空*/  
    138.             ret = fb->fb_ioctl(info, cmd, arg);  
    139.         else  
    140.             ret = -ENOTTY;  
    141.         unlock_fb_info(info);  
    142.     }  
    143.     return ret;  
    144. }  

    正如2.2小结所说的,fb_fix_screeninfo只能获取不能设置,因此,ioctl只提供了获取fb_fix_screeninfo的方法,而没有提供设置fb_fix_screeninfo的方法。

    3.5 小结

      本节对frambuffer的核心层进行了介绍。包括frambuffer子系统的创建,frambuffer的注册和提供给用户空间的5个API函数。下面开始介绍驱动层。

    4. 驱动层

    本节将开始介绍S3C2440的frambuffer驱动,该驱动源码位于drivers/video/s3c2410fb.c

    首先来看下驱动模块的初始化和清除函数。

    4.1 s3c2410fb_init和s3c2410fb_cleanup

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static struct platform_driver s3c2410fb_driver = {  
    2.     .probe        = s3c2410fb_probe,  
    3.     .remove        = s3c2410fb_remove,  
    4.     .suspend    = s3c2410fb_suspend,  
    5.     .resume        = s3c2410fb_resume,  
    6.     .driver        = {  
    7.         .name    = "s3c2410-lcd",  
    8.         .owner    = THIS_MODULE,  
    9.     },  
    10. };  
    11.   
    12. int __init s3c2410fb_init(void)  
    13. {  
    14.     int ret = platform_driver_register(&s3c2410fb_driver);  
    15.   
    16.     if (ret == 0)  
    17.         ret = platform_driver_register(&s3c2412fb_driver);;  
    18.   
    19.     return ret;  
    20. }  
    21.   
    22. static void __exit s3c2410fb_cleanup(void)  
    23. {  
    24.     platform_driver_unregister(&s3c2410fb_driver);  
    25.     platform_driver_unregister(&s3c2412fb_driver);  
    26. }  
    27.   
    28. module_init(s3c2410fb_init);  
    29. module_exit(s3c2410fb_cleanup);  
    [cpp] view plain copy
     
    1. static struct platform_driver s3c2410fb_driver = {  
    2.     .probe        = s3c2410fb_probe,  
    3.     .remove        = s3c2410fb_remove,  
    4.     .suspend    = s3c2410fb_suspend,  
    5.     .resume        = s3c2410fb_resume,  
    6.     .driver        = {  
    7.         .name    = "s3c2410-lcd",  
    8.         .owner    = THIS_MODULE,  
    9.     },  
    10. };  
    11.   
    12. int __init s3c2410fb_init(void)  
    13. {  
    14.     int ret = platform_driver_register(&s3c2410fb_driver);  
    15.   
    16.     if (ret == 0)  
    17.         ret = platform_driver_register(&s3c2412fb_driver);;  
    18.   
    19.     return ret;  
    20. }  
    21.   
    22. static void __exit s3c2410fb_cleanup(void)  
    23. {  
    24.     platform_driver_unregister(&s3c2410fb_driver);  
    25.     platform_driver_unregister(&s3c2412fb_driver);  
    26. }  
    27.   
    28. module_init(s3c2410fb_init);  
    29. module_exit(s3c2410fb_cleanup);  


    当platform_driver_register调用的最后会调用probe方法。接下来就来看看probe方法。

    4.2 probe方法

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct s3c2410fb_info {  
    2.     struct device        *dev;  
    3.     struct clk        *clk;  
    4.   
    5.     struct resource        *mem;  
    6.     void __iomem        *io;        /*虚拟地址*/  
    7.     void __iomem        *irq_base;  
    8.   
    9.     enum s3c_drv_type    drv_type;  
    10.     struct s3c2410fb_hw    regs;  
    11.   
    12.     unsigned int        palette_ready;  
    13.   
    14.     /* keep these registers in case we need to re-write palette */  
    15.     u32            palette_buffer[256];  
    16.     u32            pseudo_pal[16];  
    17. };  
    18.   
    19. struct s3c2410fb_mach_info {  
    20.   
    21.     struct s3c2410fb_display *displays; /* attached diplays info */  
    22.     unsigned num_displays;          /* number of defined displays */  
    23.     unsigned default_display;  
    24.   
    25.     /* GPIOs */  
    26.   
    27.     unsigned long   gpcup;  
    28.     unsigned long   gpcup_mask;  
    29.     unsigned long   gpccon;  
    30.     unsigned long   gpccon_mask;  
    31.     unsigned long   gpdup;  
    32.     unsigned long   gpdup_mask;  
    33.     unsigned long   gpdcon;  
    34.     unsigned long   gpdcon_mask;  
    35.   
    36.     /* lpc3600 control register */  
    37.     unsigned long   lpcsel;  
    38. };  
    39.   
    40. /* LCD description */  
    41. struct s3c2410fb_display {  
    42.     /* LCD type */  
    43.     unsigned type;  
    44.   
    45.     /* Screen size */  
    46.     unsigned short width;  
    47.     unsigned short height;  
    48.   
    49.     /* Screen info */  
    50.     unsigned short xres;  
    51.     unsigned short yres;  
    52.     unsigned short bpp;  
    53.   
    54.     unsigned pixclock;        /* pixclock in picoseconds */  
    55.     unsigned short left_margin;  /* value in pixels (TFT) or HCLKs (STN) */  
    56.     unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */  
    57.     unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */  
    58.     unsigned short upper_margin;    /* value in lines (TFT) or 0 (STN) */  
    59.     unsigned short lower_margin;    /* value in lines (TFT) or 0 (STN) */  
    60.     unsigned short vsync_len;    /* value in lines (TFT) or 0 (STN) */  
    61.   
    62.     /* lcd configuration registers */  
    63.     unsigned long    lcdcon5;  
    64. };  
    65.   
    66. static int __init s3c24xxfb_probe(struct platform_device *pdev,  
    67.                   enum s3c_drv_type drv_type)  
    68. {  
    69.     struct s3c2410fb_info *info;  
    70.     struct s3c2410fb_display *display;  
    71.     struct fb_info *fbinfo;  
    72.     struct s3c2410fb_mach_info *mach_info;  
    73.     struct resource *res;  
    74.     int ret;  
    75.     int irq;  
    76.     int i;  
    77.     int size;  
    78.     u32 lcdcon1;  
    79.     /*dev.platform_data由函数s3c24xx_fb_set_platdata(mach-smdk2410.c)设置,指向s3c2410fb_mach_info*/  
    80.     mach_info = pdev->dev.platform_data;      
    81.     if (mach_info == NULL) {  
    82.         dev_err(&pdev->dev,  
    83.             "no platform data for lcd, cannot attach ");  
    84.         return -EINVAL;  
    85.     }  
    86.                                     /*在mach-smdk2440.c中,default_display=0, num_displays=1*/  
    87.     if (mach_info->default_display >= mach_info->num_displays) {       
    88.         dev_err(&pdev->dev, "default is %d but only %d displays ",  
    89.             mach_info->default_display, mach_info->num_displays);  
    90.         return -EINVAL;  
    91.     }  
    92.   
    93.     display = mach_info->displays + mach_info->default_display;  
    94.   
    95.     irq = platform_get_irq(pdev, 0);    /*获取IRQ号,16号中断*/  
    96.     if (irq < 0) {  
    97.         dev_err(&pdev->dev, "no irq for device ");  
    98.         return -ENOENT;  
    99.     }  
    100.                                         /*分配struct fb_info 其中包括sizeof字节的私有数据区*/  
    101.     fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);  
    102.     if (!fbinfo)  
    103.         return -ENOMEM;  
    104.   
    105.     platform_set_drvdata(pdev, fbinfo);    /*让platform_device->dev.driver_data指向struct fb_info*/  
    106.   
    107.     info = fbinfo->par;                    /*par指向s3c2410fb_info*/  
    108.     info->dev = &pdev->dev;  
    109.     info->drv_type = drv_type;  
    110.   
    111.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);/*获取平台资源*/  
    112.     if (res == NULL) {  
    113.         dev_err(&pdev->dev, "failed to get memory registers ");  
    114.         ret = -ENXIO;  
    115.         goto dealloc_fb;  
    116.     }  
    117.   
    118.     size = (res->end - res->start) + 1;                /*IO内存申请*/  
    119.     info->mem = request_mem_region(res->start, size, pdev->name);      
    120.     if (info->mem == NULL) {  
    121.         dev_err(&pdev->dev, "failed to get memory region ");  
    122.         ret = -ENOENT;  
    123.         goto dealloc_fb;  
    124.     }  
    125.   
    126.     info->io = ioremap(res->start, size);            /*IO内存映射,获取lcd第一个寄存器的映射地址*/                  
    127.     if (info->io == NULL) {  
    128.         dev_err(&pdev->dev, "ioremap() of registers failed ");          
    129.         ret = -ENXIO;      
    130.         goto release_mem;  
    131.     }  
    132.                                             /*irq_base对应的物理地址是0X4D00 0054(寄存器LCDINTPND)*/  
    133.     info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);  
    134.                                                                               
    135.     dprintk("devinit ");  
    136.   
    137.     strcpy(fbinfo->fix.id, driver_name);    /*复制名字*/  
    138.   
    139.     /* Stop the video */  
    140.     lcdcon1 = readl(info->io + S3C2410_LCDCON1);  
    141.     writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); /*禁止LCD*/  
    142.   
    143.     fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;  
    144.     fbinfo->fix.type_aux        = 0;  
    145.     fbinfo->fix.xpanstep        = 0;  
    146.     fbinfo->fix.ypanstep        = 0;  
    147.     fbinfo->fix.ywrapstep        = 0;  
    148.     fbinfo->fix.accel        = FB_ACCEL_NONE;    /* no hardware accelerator    */  
    149.   
    150.     fbinfo->var.nonstd        = 0;  
    151.     fbinfo->var.activate        = FB_ACTIVATE_NOW;  
    152.     fbinfo->var.accel_flags     = 0;  
    153.     fbinfo->var.vmode        = FB_VMODE_NONINTERLACED;  
    154.   
    155.     fbinfo->fbops            = &s3c2410fb_ops;  
    156.     fbinfo->flags            = FBINFO_FLAG_DEFAULT;  
    157.     fbinfo->pseudo_palette      = &info->pseudo_pal;  
    158.   
    159.     for (i = 0; i < 256; i++)  
    160.         info->palette_buffer[i] = PALETTE_BUFF_CLEAR;  
    161.   
    162.     ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);    /*申请IRQ,快速中断*/  
    163.     if (ret) {  
    164.         dev_err(&pdev->dev, "cannot get irq %d - err %d ", irq, ret);  
    165.         ret = -EBUSY;  
    166.         goto release_regs;  
    167.     }  
    168.   
    169.     info->clk = clk_get(NULL, "lcd");        /*获取时钟信息*/  
    170.     if (!info->clk || IS_ERR(info->clk)) {  
    171.         printk(KERN_ERR "failed to get lcd clock source ");  
    172.         ret = -ENOENT;  
    173.         goto release_irq;  
    174.     }  
    175.   
    176.     clk_enable(info->clk);                    /*使能时钟*/  
    177.     dprintk("got and enabled clock ");  
    178.   
    179.     msleep(1);  
    180.   
    181.     /* find maximum required memory size for display */  
    182.     /*在多个屏幕中,找出需要的最大memory*/  
    183.     for (i = 0; i < mach_info->num_displays; i++) {  
    184.         unsigned long smem_len = mach_info->displays[i].xres;  
    185.         /*所需的memory空间 = xres * yres * bpp / 8*/  
    186.         smem_len *= mach_info->displays[i].yres;  
    187.         smem_len *= mach_info->displays[i].bpp;  
    188.         smem_len >>= 3;  
    189.         if (fbinfo->fix.smem_len < smem_len)  
    190.             fbinfo->fix.smem_len = smem_len;  
    191.     }  
    192.   
    193.     /* Initialize video memory */    /*根据上面fix.smem_len的大小,获取DMA映射内存,一致性映射方式*/  
    194.     ret = s3c2410fb_map_video_memory(fbinfo);  
    195.     if (ret) {  
    196.         printk(KERN_ERR "Failed to allocate video RAM: %d ", ret);  
    197.         ret = -ENOMEM;  
    198.         goto release_clock;  
    199.     }  
    200.   
    201.     dprintk("got video memory ");  
    202.   
    203.     fbinfo->var.xres = display->xres;            /*320*/  
    204.     fbinfo->var.yres = display->yres;            /*240*/      
    205.     fbinfo->var.bits_per_pixel = display->bpp;    /*16*/  
    206.   
    207.     s3c2410fb_init_registers(fbinfo);            /*LCD寄存器初始化*/          
    208.   
    209.     s3c2410fb_check_var(&fbinfo->var, fbinfo);  
    210.   
    211.     ret = register_framebuffer(fbinfo);            /*注册framebuffer*/  
    212.     if (ret < 0) {  
    213.         printk(KERN_ERR "Failed to register framebuffer device: %d ",ret);  
    214.         goto free_video_memory;  
    215.     }  
    216.   
    217.     /* create device files */  
    218.     ret = device_create_file(&pdev->dev, &dev_attr_debug); /*添加设备属性*/  
    219.     if (ret) {  
    220.         printk(KERN_ERR "failed to add debug attribute ");  
    221.     }  
    222.   
    223.     printk(KERN_INFO "fb%d: %s frame buffer device ",  
    224.         fbinfo->node, fbinfo->fix.id);  
    225.   
    226.     return 0;  
    227. /*一旦某个步骤发生错误,以注册的相反顺序开始注销*/  
    228. free_video_memory:  
    229.     s3c2410fb_unmap_video_memory(fbinfo);  
    230. release_clock:  
    231.     clk_disable(info->clk);  
    232.     clk_put(info->clk);  
    233. release_irq:  
    234.     free_irq(irq, info);  
    235. release_regs:  
    236.     iounmap(info->io);  
    237. release_mem:  
    238.     release_resource(info->mem);  
    239.     kfree(info->mem);  
    240. dealloc_fb:  
    241.     platform_set_drvdata(pdev, NULL);  
    242.     framebuffer_release(fbinfo);      
    243.     return ret;  
    244. }  
    [cpp] view plain copy
     
    1. struct s3c2410fb_info {  
    2.     struct device        *dev;  
    3.     struct clk        *clk;  
    4.   
    5.     struct resource        *mem;  
    6.     void __iomem        *io;        /*虚拟地址*/  
    7.     void __iomem        *irq_base;  
    8.   
    9.     enum s3c_drv_type    drv_type;  
    10.     struct s3c2410fb_hw    regs;  
    11.   
    12.     unsigned int        palette_ready;  
    13.   
    14.     /* keep these registers in case we need to re-write palette */  
    15.     u32            palette_buffer[256];  
    16.     u32            pseudo_pal[16];  
    17. };  
    18.   
    19. struct s3c2410fb_mach_info {  
    20.   
    21.     struct s3c2410fb_display *displays; /* attached diplays info */  
    22.     unsigned num_displays;          /* number of defined displays */  
    23.     unsigned default_display;  
    24.   
    25.     /* GPIOs */  
    26.   
    27.     unsigned long   gpcup;  
    28.     unsigned long   gpcup_mask;  
    29.     unsigned long   gpccon;  
    30.     unsigned long   gpccon_mask;  
    31.     unsigned long   gpdup;  
    32.     unsigned long   gpdup_mask;  
    33.     unsigned long   gpdcon;  
    34.     unsigned long   gpdcon_mask;  
    35.   
    36.     /* lpc3600 control register */  
    37.     unsigned long   lpcsel;  
    38. };  
    39.   
    40. /* LCD description */  
    41. struct s3c2410fb_display {  
    42.     /* LCD type */  
    43.     unsigned type;  
    44.   
    45.     /* Screen size */  
    46.     unsigned short width;  
    47.     unsigned short height;  
    48.   
    49.     /* Screen info */  
    50.     unsigned short xres;  
    51.     unsigned short yres;  
    52.     unsigned short bpp;  
    53.   
    54.     unsigned pixclock;        /* pixclock in picoseconds */  
    55.     unsigned short left_margin;  /* value in pixels (TFT) or HCLKs (STN) */  
    56.     unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */  
    57.     unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */  
    58.     unsigned short upper_margin;    /* value in lines (TFT) or 0 (STN) */  
    59.     unsigned short lower_margin;    /* value in lines (TFT) or 0 (STN) */  
    60.     unsigned short vsync_len;    /* value in lines (TFT) or 0 (STN) */  
    61.   
    62.     /* lcd configuration registers */  
    63.     unsigned long    lcdcon5;  
    64. };  
    65.   
    66. static int __init s3c24xxfb_probe(struct platform_device *pdev,  
    67.                   enum s3c_drv_type drv_type)  
    68. {  
    69.     struct s3c2410fb_info *info;  
    70.     struct s3c2410fb_display *display;  
    71.     struct fb_info *fbinfo;  
    72.     struct s3c2410fb_mach_info *mach_info;  
    73.     struct resource *res;  
    74.     int ret;  
    75.     int irq;  
    76.     int i;  
    77.     int size;  
    78.     u32 lcdcon1;  
    79.     /*dev.platform_data由函数s3c24xx_fb_set_platdata(mach-smdk2410.c)设置,指向s3c2410fb_mach_info*/  
    80.     mach_info = pdev->dev.platform_data;      
    81.     if (mach_info == NULL) {  
    82.         dev_err(&pdev->dev,  
    83.             "no platform data for lcd, cannot attach ");  
    84.         return -EINVAL;  
    85.     }  
    86.                                     /*在mach-smdk2440.c中,default_display=0, num_displays=1*/  
    87.     if (mach_info->default_display >= mach_info->num_displays) {       
    88.         dev_err(&pdev->dev, "default is %d but only %d displays ",  
    89.             mach_info->default_display, mach_info->num_displays);  
    90.         return -EINVAL;  
    91.     }  
    92.   
    93.     display = mach_info->displays + mach_info->default_display;  
    94.   
    95.     irq = platform_get_irq(pdev, 0);    /*获取IRQ号,16号中断*/  
    96.     if (irq < 0) {  
    97.         dev_err(&pdev->dev, "no irq for device ");  
    98.         return -ENOENT;  
    99.     }  
    100.                                         /*分配struct fb_info 其中包括sizeof字节的私有数据区*/  
    101.     fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);  
    102.     if (!fbinfo)  
    103.         return -ENOMEM;  
    104.   
    105.     platform_set_drvdata(pdev, fbinfo);    /*让platform_device->dev.driver_data指向struct fb_info*/  
    106.   
    107.     info = fbinfo->par;                    /*par指向s3c2410fb_info*/  
    108.     info->dev = &pdev->dev;  
    109.     info->drv_type = drv_type;  
    110.   
    111.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);/*获取平台资源*/  
    112.     if (res == NULL) {  
    113.         dev_err(&pdev->dev, "failed to get memory registers ");  
    114.         ret = -ENXIO;  
    115.         goto dealloc_fb;  
    116.     }  
    117.   
    118.     size = (res->end - res->start) + 1;                /*IO内存申请*/  
    119.     info->mem = request_mem_region(res->start, size, pdev->name);      
    120.     if (info->mem == NULL) {  
    121.         dev_err(&pdev->dev, "failed to get memory region ");  
    122.         ret = -ENOENT;  
    123.         goto dealloc_fb;  
    124.     }  
    125.   
    126.     info->io = ioremap(res->start, size);            /*IO内存映射,获取lcd第一个寄存器的映射地址*/                  
    127.     if (info->io == NULL) {  
    128.         dev_err(&pdev->dev, "ioremap() of registers failed ");          
    129.         ret = -ENXIO;      
    130.         goto release_mem;  
    131.     }  
    132.                                             /*irq_base对应的物理地址是0X4D00 0054(寄存器LCDINTPND)*/  
    133.     info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);  
    134.                                                                               
    135.     dprintk("devinit ");  
    136.   
    137.     strcpy(fbinfo->fix.id, driver_name);    /*复制名字*/  
    138.   
    139.     /* Stop the video */  
    140.     lcdcon1 = readl(info->io + S3C2410_LCDCON1);  
    141.     writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); /*禁止LCD*/  
    142.   
    143.     fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;  
    144.     fbinfo->fix.type_aux        = 0;  
    145.     fbinfo->fix.xpanstep        = 0;  
    146.     fbinfo->fix.ypanstep        = 0;  
    147.     fbinfo->fix.ywrapstep        = 0;  
    148.     fbinfo->fix.accel        = FB_ACCEL_NONE;    /* no hardware accelerator    */  
    149.   
    150.     fbinfo->var.nonstd        = 0;  
    151.     fbinfo->var.activate        = FB_ACTIVATE_NOW;  
    152.     fbinfo->var.accel_flags     = 0;  
    153.     fbinfo->var.vmode        = FB_VMODE_NONINTERLACED;  
    154.   
    155.     fbinfo->fbops            = &s3c2410fb_ops;  
    156.     fbinfo->flags            = FBINFO_FLAG_DEFAULT;  
    157.     fbinfo->pseudo_palette      = &info->pseudo_pal;  
    158.   
    159.     for (i = 0; i < 256; i++)  
    160.         info->palette_buffer[i] = PALETTE_BUFF_CLEAR;  
    161.   
    162.     ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);    /*申请IRQ,快速中断*/  
    163.     if (ret) {  
    164.         dev_err(&pdev->dev, "cannot get irq %d - err %d ", irq, ret);  
    165.         ret = -EBUSY;  
    166.         goto release_regs;  
    167.     }  
    168.   
    169.     info->clk = clk_get(NULL, "lcd");        /*获取时钟信息*/  
    170.     if (!info->clk || IS_ERR(info->clk)) {  
    171.         printk(KERN_ERR "failed to get lcd clock source ");  
    172.         ret = -ENOENT;  
    173.         goto release_irq;  
    174.     }  
    175.   
    176.     clk_enable(info->clk);                    /*使能时钟*/  
    177.     dprintk("got and enabled clock ");  
    178.   
    179.     msleep(1);  
    180.   
    181.     /* find maximum required memory size for display */  
    182.     /*在多个屏幕中,找出需要的最大memory*/  
    183.     for (i = 0; i < mach_info->num_displays; i++) {  
    184.         unsigned long smem_len = mach_info->displays[i].xres;  
    185.         /*所需的memory空间 = xres * yres * bpp / 8*/  
    186.         smem_len *= mach_info->displays[i].yres;  
    187.         smem_len *= mach_info->displays[i].bpp;  
    188.         smem_len >>= 3;  
    189.         if (fbinfo->fix.smem_len < smem_len)  
    190.             fbinfo->fix.smem_len = smem_len;  
    191.     }  
    192.   
    193.     /* Initialize video memory */    /*根据上面fix.smem_len的大小,获取DMA映射内存,一致性映射方式*/  
    194.     ret = s3c2410fb_map_video_memory(fbinfo);  
    195.     if (ret) {  
    196.         printk(KERN_ERR "Failed to allocate video RAM: %d ", ret);  
    197.         ret = -ENOMEM;  
    198.         goto release_clock;  
    199.     }  
    200.   
    201.     dprintk("got video memory ");  
    202.   
    203.     fbinfo->var.xres = display->xres;            /*320*/  
    204.     fbinfo->var.yres = display->yres;            /*240*/      
    205.     fbinfo->var.bits_per_pixel = display->bpp;    /*16*/  
    206.   
    207.     s3c2410fb_init_registers(fbinfo);            /*LCD寄存器初始化*/          
    208.   
    209.     s3c2410fb_check_var(&fbinfo->var, fbinfo);  
    210.   
    211.     ret = register_framebuffer(fbinfo);            /*注册framebuffer*/  
    212.     if (ret < 0) {  
    213.         printk(KERN_ERR "Failed to register framebuffer device: %d ",ret);  
    214.         goto free_video_memory;  
    215.     }  
    216.   
    217.     /* create device files */  
    218.     ret = device_create_file(&pdev->dev, &dev_attr_debug); /*添加设备属性*/  
    219.     if (ret) {  
    220.         printk(KERN_ERR "failed to add debug attribute ");  
    221.     }  
    222.   
    223.     printk(KERN_INFO "fb%d: %s frame buffer device ",  
    224.         fbinfo->node, fbinfo->fix.id);  
    225.   
    226.     return 0;  
    227. /*一旦某个步骤发生错误,以注册的相反顺序开始注销*/  
    228. free_video_memory:  
    229.     s3c2410fb_unmap_video_memory(fbinfo);  
    230. release_clock:  
    231.     clk_disable(info->clk);  
    232.     clk_put(info->clk);  
    233. release_irq:  
    234.     free_irq(irq, info);  
    235. release_regs:  
    236.     iounmap(info->io);  
    237. release_mem:  
    238.     release_resource(info->mem);  
    239.     kfree(info->mem);  
    240. dealloc_fb:  
    241.     platform_set_drvdata(pdev, NULL);  
    242.     framebuffer_release(fbinfo);      
    243.     return ret;  
    244. }  

    这里使用了三个新的数据结构。s3c2410fb_info是驱动程序使用的,里面将保存所有驱动程序所要使用的资源等。而s3c2410fb_display和s3c2410fb_mach_info,是由板级信息,通过platform总线添加到内核中。

    s3c2410fb_display中的成员将被复制到fb_var_screeninfo结构中。

    该板级信息的定义在arch/arm/mach-s3c2440/mach-smdk2440.c中,来看下

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {  
    2.   
    3.     .lcdcon5    = S3C2410_LCDCON5_FRM565 |  
    4.               S3C2410_LCDCON5_INVVLINE |  
    5.               S3C2410_LCDCON5_INVVFRAME |  
    6.               S3C2410_LCDCON5_PWREN |  
    7.               S3C2410_LCDCON5_HWSWP,  
    8.   
    9.     .type       = S3C2410_LCDCON1_TFT,  
    10.   
    11.     .width      = 320,//240,   
    12.     .height     = 240,//320,   
    13.   
    14.     .pixclock   = 149000,//166667, /* HCLK 60 MHz, divisor 10 */   
    15.     .xres       = 320,//240,   
    16.     .yres       = 240,//320,   
    17.     .bpp        = 16,  
    18.     .left_margin    = 20,  
    19.     .right_margin   = 38,//8,   
    20.     .hsync_len  = 30,//4,   
    21.     .upper_margin   = 15,//8,   
    22.     .lower_margin   = 12,//7,   
    23.     .vsync_len  = 3,//4,   
    24. };  
    25.   
    26. static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {  
    27.     .displays   = &smdk2440_lcd_cfg,  
    28.     .num_displays   = 1,  
    29.     .default_display = 0,  
    30.   
    31. #if 0   
    32.     /* currently setup by downloader */  
    33.     .gpccon     = 0xaa940659,  
    34.     .gpccon_mask    = 0xffffffff,  
    35.     .gpcup      = 0x0000ffff,  
    36.     .gpcup_mask = 0xffffffff,  
    37.     .gpdcon     = 0xaa84aaa0,  
    38.     .gpdcon_mask    = 0xffffffff,  
    39.     .gpdup      = 0x0000faff,  
    40.     .gpdup_mask = 0xffffffff,  
    41. #endif   
    42. //no   
    43. //  .lpcsel     = ((0xCE6) & ~7) | 1<<4,   
    44. };  
    [cpp] view plain copy
     
    1. static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {  
    2.   
    3.     .lcdcon5    = S3C2410_LCDCON5_FRM565 |  
    4.               S3C2410_LCDCON5_INVVLINE |  
    5.               S3C2410_LCDCON5_INVVFRAME |  
    6.               S3C2410_LCDCON5_PWREN |  
    7.               S3C2410_LCDCON5_HWSWP,  
    8.   
    9.     .type       = S3C2410_LCDCON1_TFT,  
    10.   
    11.     .width      = 320,//240,  
    12.     .height     = 240,//320,  
    13.   
    14.     .pixclock   = 149000,//166667, /* HCLK 60 MHz, divisor 10 */  
    15.     .xres       = 320,//240,  
    16.     .yres       = 240,//320,  
    17.     .bpp        = 16,  
    18.     .left_margin    = 20,  
    19.     .right_margin   = 38,//8,  
    20.     .hsync_len  = 30,//4,  
    21.     .upper_margin   = 15,//8,  
    22.     .lower_margin   = 12,//7,  
    23.     .vsync_len  = 3,//4,  
    24. };  
    25.   
    26. static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {  
    27.     .displays   = &smdk2440_lcd_cfg,  
    28.     .num_displays   = 1,  
    29.     .default_display = 0,  
    30.   
    31. #if 0  
    32.     /* currently setup by downloader */  
    33.     .gpccon     = 0xaa940659,  
    34.     .gpccon_mask    = 0xffffffff,  
    35.     .gpcup      = 0x0000ffff,  
    36.     .gpcup_mask = 0xffffffff,  
    37.     .gpdcon     = 0xaa84aaa0,  
    38.     .gpdcon_mask    = 0xffffffff,  
    39.     .gpdup      = 0x0000faff,  
    40.     .gpdup_mask = 0xffffffff,  
    41. #endif  
    42. //no  
    43. //  .lpcsel     = ((0xCE6) & ~7) | 1<<4,  
    44. };  

    这里NOTE:每个LCD屏幕的参数不一样,因此上面的参数会有所不同,这是需要移植的地方。

    随后,我们看下在probe方法中调用的几个函数。首先是s3c2410fb_map_video_memory。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* 
    2.  * s3c2410fb_map_video_memory(): 
    3.  *  Allocates the DRAM memory for the frame buffer.  This buffer is 
    4.  *  remapped into a non-cached, non-buffered, memory region to 
    5.  *  allow palette and pixel writes to occur without flushing the 
    6.  *  cache.  Once this area is remapped, all virtual memory 
    7.  *  access to the video memory should occur at the new region. 
    8.  */  
    9. static int __init s3c2410fb_map_video_memory(struct fb_info *info)  
    10. {  
    11.     struct s3c2410fb_info *fbi = info->par;  
    12.     dma_addr_t map_dma;  
    13.     unsigned map_size = PAGE_ALIGN(info->fix.smem_len);  
    14.   
    15.     dprintk("map_video_memory(fbi=%p) map_size %u ", fbi, map_size);  
    16.         /*分配DMA缓冲区,并保存DMA缓冲区虚拟地址*/  
    17.     info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,  
    18.                            &map_dma, GFP_KERNEL);  
    19.   
    20.     if (info->screen_base) {  
    21.         /* prevent initial garbage on screen */  
    22.         dprintk("map_video_memory: clear %p:%08x ",  
    23.             info->screen_base, map_size);  
    24.         memset(info->screen_base, 0x00, map_size);   /*DMA缓冲区清0*/  
    25.   
    26.         info->fix.smem_start = map_dma;  /*保存DMA缓冲区物理地址*/  
    27.   
    28.         dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x ",  
    29.             info->fix.smem_start, info->screen_base, map_size);  
    30.     }  
    31.   
    32.     return info->screen_base ? 0 : -ENOMEM;  
    33. }  
    [cpp] view plain copy
     
    1. /* 
    2.  * s3c2410fb_map_video_memory(): 
    3.  *  Allocates the DRAM memory for the frame buffer.  This buffer is 
    4.  *  remapped into a non-cached, non-buffered, memory region to 
    5.  *  allow palette and pixel writes to occur without flushing the 
    6.  *  cache.  Once this area is remapped, all virtual memory 
    7.  *  access to the video memory should occur at the new region. 
    8.  */  
    9. static int __init s3c2410fb_map_video_memory(struct fb_info *info)  
    10. {  
    11.     struct s3c2410fb_info *fbi = info->par;  
    12.     dma_addr_t map_dma;  
    13.     unsigned map_size = PAGE_ALIGN(info->fix.smem_len);  
    14.   
    15.     dprintk("map_video_memory(fbi=%p) map_size %u ", fbi, map_size);  
    16.         /*分配DMA缓冲区,并保存DMA缓冲区虚拟地址*/  
    17.     info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,  
    18.                            &map_dma, GFP_KERNEL);  
    19.   
    20.     if (info->screen_base) {  
    21.         /* prevent initial garbage on screen */  
    22.         dprintk("map_video_memory: clear %p:%08x ",  
    23.             info->screen_base, map_size);  
    24.         memset(info->screen_base, 0x00, map_size);   /*DMA缓冲区清0*/  
    25.   
    26.         info->fix.smem_start = map_dma;  /*保存DMA缓冲区物理地址*/  
    27.   
    28.         dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x ",  
    29.             info->fix.smem_start, info->screen_base, map_size);  
    30.     }  
    31.   
    32.     return info->screen_base ? 0 : -ENOMEM;  
    33. }  



    该函数根据fix.smem_len的大小,分配了一个DMA缓冲区,保存了该缓冲区的物理地址和虚拟地址。

    接着是s3c2410fb_init_registers:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* 
    2.  * s3c2410fb_init_registers - Initialise all LCD-related registers 
    3.  */  
    4. static int s3c2410fb_init_registers(struct fb_info *info)  
    5. {  
    6.     struct s3c2410fb_info *fbi = info->par;        /*par指向s3c2410fb_info*/  
    7.     struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;  
    8.     unsigned long flags;  
    9.     void __iomem *regs = fbi->io;  
    10.     void __iomem *tpal;  
    11.     void __iomem *lpcsel;  
    12.   
    13.     if (is_s3c2412(fbi)) {  
    14.         tpal = regs + S3C2412_TPAL;  
    15.         lpcsel = regs + S3C2412_TCONSEL;  
    16.     } else {  
    17.         tpal = regs + S3C2410_TPAL;  
    18.         lpcsel = regs + S3C2410_LPCSEL;  
    19.     }  
    20.   
    21.     /* Initialise LCD with values from haret */  
    22.   
    23.     local_irq_save(flags);                        /*禁止所有中断*/  
    24.   
    25.     /* modify the gpio(s) with interrupts set (bjd) */    /*初始化io管脚*/  
    26.   
    27.     modify_gpio(S3C2410_GPCUP,  mach_info->gpcup,  mach_info->gpcup_mask);  
    28.     modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);  
    29.     modify_gpio(S3C2410_GPDUP,  mach_info->gpdup,  mach_info->gpdup_mask);  
    30.     modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);  
    31.   
    32.     local_irq_restore(flags);                    /*恢复中断*/  
    33.   
    34.     dprintk("LPCSEL    = 0x%08lx ", mach_info->lpcsel);    /*设置TCONSEL,禁止LPC3600*/  
    35.     writel(mach_info->lpcsel, lpcsel);  
    36.   
    37.     dprintk("replacing TPAL %08x ", readl(tpal));  
    38.   
    39.     /* ensure temporary palette disabled */  
    40.     writel(0x00, tpal);    /*禁止调色板*/  
    41.   
    42.     return 0;  
    43. }  
    44.   
    45. static inline void modify_gpio(void __iomem *reg,  
    46.                    unsigned long set, unsigned long mask)  
    47. {  
    48.     unsigned long tmp;  
    49.   
    50.     tmp = readl(reg) & ~mask;  
    51.     writel(tmp | set, reg);  
    52. }   
    [cpp] view plain copy
     
    1. /* 
    2.  * s3c2410fb_init_registers - Initialise all LCD-related registers 
    3.  */  
    4. static int s3c2410fb_init_registers(struct fb_info *info)  
    5. {  
    6.     struct s3c2410fb_info *fbi = info->par;        /*par指向s3c2410fb_info*/  
    7.     struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;  
    8.     unsigned long flags;  
    9.     void __iomem *regs = fbi->io;  
    10.     void __iomem *tpal;  
    11.     void __iomem *lpcsel;  
    12.   
    13.     if (is_s3c2412(fbi)) {  
    14.         tpal = regs + S3C2412_TPAL;  
    15.         lpcsel = regs + S3C2412_TCONSEL;  
    16.     } else {  
    17.         tpal = regs + S3C2410_TPAL;  
    18.         lpcsel = regs + S3C2410_LPCSEL;  
    19.     }  
    20.   
    21.     /* Initialise LCD with values from haret */  
    22.   
    23.     local_irq_save(flags);                        /*禁止所有中断*/  
    24.   
    25.     /* modify the gpio(s) with interrupts set (bjd) */    /*初始化io管脚*/  
    26.   
    27.     modify_gpio(S3C2410_GPCUP,  mach_info->gpcup,  mach_info->gpcup_mask);  
    28.     modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);  
    29.     modify_gpio(S3C2410_GPDUP,  mach_info->gpdup,  mach_info->gpdup_mask);  
    30.     modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);  
    31.   
    32.     local_irq_restore(flags);                    /*恢复中断*/  
    33.   
    34.     dprintk("LPCSEL    = 0x%08lx ", mach_info->lpcsel);    /*设置TCONSEL,禁止LPC3600*/  
    35.     writel(mach_info->lpcsel, lpcsel);  
    36.   
    37.     dprintk("replacing TPAL %08x ", readl(tpal));  
    38.   
    39.     /* ensure temporary palette disabled */  
    40.     writel(0x00, tpal);    /*禁止调色板*/  
    41.   
    42.     return 0;  
    43. }  
    44.   
    45. static inline void modify_gpio(void __iomem *reg,  
    46.                    unsigned long set, unsigned long mask)  
    47. {  
    48.     unsigned long tmp;  
    49.   
    50.     tmp = readl(reg) & ~mask;  
    51.     writel(tmp | set, reg);  
    52. }   

    最后是s3c2410fb_check_var:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* 
    2.  *  s3c2410fb_check_var(): 
    3.  *  Get the video params out of 'var'. If a value doesn't fit, round it up, 
    4.  *  if it's too big, return -EINVAL. 
    5.  *  检查变量的合法性 
    6.  */  
    7. static int s3c2410fb_check_var(struct fb_var_screeninfo *var,  
    8.                    struct fb_info *info)  
    9. {  
    10.     struct s3c2410fb_info *fbi = info->par;          /*par指向s3c2410fb_info*/  
    11.     struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;/*指向s3c2410fb_mach_info*/  
    12.     struct s3c2410fb_display *display = NULL;  
    13.     struct s3c2410fb_display *default_display = mach_info->displays +  
    14.                             mach_info->default_display;  
    15.     int type = default_display->type;    /*S3C2410_LCDCON1_TFT*/  
    16.     unsigned i;  
    17.   
    18.     dprintk("check_var(var=%p, info=%p) ", var, info);  
    19.   
    20.     /* validate x/y resolution */  
    21.     /* choose default mode if possible */           /*var中的成员在probe中设置*/  
    22.     if (var->yres == default_display->yres &&  
    23.         var->xres == default_display->xres &&  
    24.         var->bits_per_pixel == default_display->bpp)  
    25.         display = default_display;  
    26.     else  
    27.         for (i = 0; i < mach_info->num_displays; i++)  
    28.             if (type == mach_info->displays[i].type &&  
    29.                 var->yres == mach_info->displays[i].yres &&  
    30.                 var->xres == mach_info->displays[i].xres &&  
    31.                 var->bits_per_pixel == mach_info->displays[i].bpp) {  
    32.                 display = mach_info->displays + i;  
    33.                 break;  
    34.             }  
    35.   
    36.     if (!display) {  
    37.         dprintk("wrong resolution or depth %dx%d at %d bpp ",  
    38.             var->xres, var->yres, var->bits_per_pixel);  
    39.         return -EINVAL;  
    40.     }  
    41.   
    42.     /* it is always the size as the display */  
    43.     var->xres_virtual = display->xres;  
    44.     var->yres_virtual = display->yres;  
    45.     var->height = display->height;  
    46.     var->width = display->width;  
    47.   
    48.     /* copy lcd settings */  
    49.     var->pixclock = display->pixclock;  
    50.     var->left_margin = display->left_margin;  
    51.     var->right_margin = display->right_margin;  
    52.     var->upper_margin = display->upper_margin;  
    53.     var->lower_margin = display->lower_margin;  
    54.     var->vsync_len = display->vsync_len;  
    55.     var->hsync_len = display->hsync_len;  
    56.   
    57.     fbi->regs.lcdcon5 = display->lcdcon5;  
    58.     /* set display type */  
    59.     fbi->regs.lcdcon1 = display->type;  
    60.   
    61.     var->transp.offset = 0;  
    62.     var->transp.length = 0;  
    63.     /* set r/g/b positions */  
    64.     switch (var->bits_per_pixel) {  
    65.     case 1:  
    66.     case 2:  
    67.     case 4:  
    68.         var->red.offset  = 0;  
    69.         var->red.length  = var->bits_per_pixel;  
    70.         var->green   = var->red;  
    71.         var->blue    = var->red;  
    72.         break;  
    73.     case 8:  
    74.         if (display->type != S3C2410_LCDCON1_TFT) {  
    75.             /* 8 bpp 332 */  
    76.             var->red.length      = 3;  
    77.             var->red.offset      = 5;  
    78.             var->green.length    = 3;  
    79.             var->green.offset    = 2;  
    80.             var->blue.length = 2;  
    81.             var->blue.offset = 0;  
    82.         } else {  
    83.             var->red.offset      = 0;  
    84.             var->red.length      = 8;  
    85.             var->green       = var->red;  
    86.             var->blue        = var->red;  
    87.         }  
    88.         break;  
    89.     case 12:  
    90.         /* 12 bpp 444 */  
    91.         var->red.length      = 4;  
    92.         var->red.offset      = 8;  
    93.         var->green.length    = 4;  
    94.         var->green.offset    = 4;  
    95.         var->blue.length = 4;  
    96.         var->blue.offset = 0;  
    97.         break;  
    98.   
    99.     default:  
    100.     case 16:  
    101.         if (display->lcdcon5 & S3C2410_LCDCON5_FRM565) { /*使用565格式*/  
    102.             /* 16 bpp, 565 format */  
    103.             var->red.offset      = 11;  
    104.             var->green.offset    = 5;  
    105.             var->blue.offset = 0;  
    106.             var->red.length      = 5;  
    107.             var->green.length    = 6;  
    108.             var->blue.length = 5;  
    109.         } else {  
    110.             /* 16 bpp, 5551 format */  
    111.             var->red.offset      = 11;  
    112.             var->green.offset    = 6;  
    113.             var->blue.offset = 1;  
    114.             var->red.length      = 5;  
    115.             var->green.length    = 5;  
    116.             var->blue.length = 5;  
    117.         }  
    118.         break;  
    119.     case 32:  
    120.         /* 24 bpp 888 and 8 dummy */  
    121.         var->red.length      = 8;  
    122.         var->red.offset      = 16;  
    123.         var->green.length    = 8;  
    124.         var->green.offset    = 8;  
    125.         var->blue.length = 8;  
    126.         var->blue.offset = 0;  
    127.         break;  
    128.     }  
    129.     return 0;  
    130. }  
    131.   
    132. /* Interpretation of offset for color fields: All offsets are from the right, 
    133.  * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you 
    134.  * can use the offset as right argument to <<). A pixel afterwards is a bit 
    135.  * stream and is written to video memory as that unmodified. 
    136.  * 
    137.  * For pseudocolor: offset and length should be the same for all color 
    138.  * components. Offset specifies the position of the least significant bit 
    139.  * of the pallette index in a pixel value. Length indicates the number 
    140.  * of available palette entries (i.e. # of entries = 1 << length). 
    141.  */  
    142. struct fb_bitfield {  
    143.     __u32 offset;            /* beginning of bitfield    */  
    144.     __u32 length;            /* length of bitfield        */  
    145.     __u32 msb_right;        /* != 0 : Most significant bit is */   
    146.                     /* right */   
    147. };  
    [cpp] view plain copy
     
    1. /* 
    2.  *  s3c2410fb_check_var(): 
    3.  *  Get the video params out of 'var'. If a value doesn't fit, round it up, 
    4.  *  if it's too big, return -EINVAL. 
    5.  *  检查变量的合法性 
    6.  */  
    7. static int s3c2410fb_check_var(struct fb_var_screeninfo *var,  
    8.                    struct fb_info *info)  
    9. {  
    10.     struct s3c2410fb_info *fbi = info->par;          /*par指向s3c2410fb_info*/  
    11.     struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;/*指向s3c2410fb_mach_info*/  
    12.     struct s3c2410fb_display *display = NULL;  
    13.     struct s3c2410fb_display *default_display = mach_info->displays +  
    14.                             mach_info->default_display;  
    15.     int type = default_display->type;    /*S3C2410_LCDCON1_TFT*/  
    16.     unsigned i;  
    17.   
    18.     dprintk("check_var(var=%p, info=%p) ", var, info);  
    19.   
    20.     /* validate x/y resolution */  
    21.     /* choose default mode if possible */           /*var中的成员在probe中设置*/  
    22.     if (var->yres == default_display->yres &&  
    23.         var->xres == default_display->xres &&  
    24.         var->bits_per_pixel == default_display->bpp)  
    25.         display = default_display;  
    26.     else  
    27.         for (i = 0; i < mach_info->num_displays; i++)  
    28.             if (type == mach_info->displays[i].type &&  
    29.                 var->yres == mach_info->displays[i].yres &&  
    30.                 var->xres == mach_info->displays[i].xres &&  
    31.                 var->bits_per_pixel == mach_info->displays[i].bpp) {  
    32.                 display = mach_info->displays + i;  
    33.                 break;  
    34.             }  
    35.   
    36.     if (!display) {  
    37.         dprintk("wrong resolution or depth %dx%d at %d bpp ",  
    38.             var->xres, var->yres, var->bits_per_pixel);  
    39.         return -EINVAL;  
    40.     }  
    41.   
    42.     /* it is always the size as the display */  
    43.     var->xres_virtual = display->xres;  
    44.     var->yres_virtual = display->yres;  
    45.     var->height = display->height;  
    46.     var->width = display->width;  
    47.   
    48.     /* copy lcd settings */  
    49.     var->pixclock = display->pixclock;  
    50.     var->left_margin = display->left_margin;  
    51.     var->right_margin = display->right_margin;  
    52.     var->upper_margin = display->upper_margin;  
    53.     var->lower_margin = display->lower_margin;  
    54.     var->vsync_len = display->vsync_len;  
    55.     var->hsync_len = display->hsync_len;  
    56.   
    57.     fbi->regs.lcdcon5 = display->lcdcon5;  
    58.     /* set display type */  
    59.     fbi->regs.lcdcon1 = display->type;  
    60.   
    61.     var->transp.offset = 0;  
    62.     var->transp.length = 0;  
    63.     /* set r/g/b positions */  
    64.     switch (var->bits_per_pixel) {  
    65.     case 1:  
    66.     case 2:  
    67.     case 4:  
    68.         var->red.offset  = 0;  
    69.         var->red.length  = var->bits_per_pixel;  
    70.         var->green   = var->red;  
    71.         var->blue    = var->red;  
    72.         break;  
    73.     case 8:  
    74.         if (display->type != S3C2410_LCDCON1_TFT) {  
    75.             /* 8 bpp 332 */  
    76.             var->red.length      = 3;  
    77.             var->red.offset      = 5;  
    78.             var->green.length    = 3;  
    79.             var->green.offset    = 2;  
    80.             var->blue.length = 2;  
    81.             var->blue.offset = 0;  
    82.         } else {  
    83.             var->red.offset      = 0;  
    84.             var->red.length      = 8;  
    85.             var->green       = var->red;  
    86.             var->blue        = var->red;  
    87.         }  
    88.         break;  
    89.     case 12:  
    90.         /* 12 bpp 444 */  
    91.         var->red.length      = 4;  
    92.         var->red.offset      = 8;  
    93.         var->green.length    = 4;  
    94.         var->green.offset    = 4;  
    95.         var->blue.length = 4;  
    96.         var->blue.offset = 0;  
    97.         break;  
    98.   
    99.     default:  
    100.     case 16:  
    101.         if (display->lcdcon5 & S3C2410_LCDCON5_FRM565) { /*使用565格式*/  
    102.             /* 16 bpp, 565 format */  
    103.             var->red.offset      = 11;  
    104.             var->green.offset    = 5;  
    105.             var->blue.offset = 0;  
    106.             var->red.length      = 5;  
    107.             var->green.length    = 6;  
    108.             var->blue.length = 5;  
    109.         } else {  
    110.             /* 16 bpp, 5551 format */  
    111.             var->red.offset      = 11;  
    112.             var->green.offset    = 6;  
    113.             var->blue.offset = 1;  
    114.             var->red.length      = 5;  
    115.             var->green.length    = 5;  
    116.             var->blue.length = 5;  
    117.         }  
    118.         break;  
    119.     case 32:  
    120.         /* 24 bpp 888 and 8 dummy */  
    121.         var->red.length      = 8;  
    122.         var->red.offset      = 16;  
    123.         var->green.length    = 8;  
    124.         var->green.offset    = 8;  
    125.         var->blue.length = 8;  
    126.         var->blue.offset = 0;  
    127.         break;  
    128.     }  
    129.     return 0;  
    130. }  
    131.   
    132. /* Interpretation of offset for color fields: All offsets are from the right, 
    133.  * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you 
    134.  * can use the offset as right argument to <<). A pixel afterwards is a bit 
    135.  * stream and is written to video memory as that unmodified. 
    136.  * 
    137.  * For pseudocolor: offset and length should be the same for all color 
    138.  * components. Offset specifies the position of the least significant bit 
    139.  * of the pallette index in a pixel value. Length indicates the number 
    140.  * of available palette entries (i.e. # of entries = 1 << length). 
    141.  */  
    142. struct fb_bitfield {  
    143.     __u32 offset;            /* beginning of bitfield    */  
    144.     __u32 length;            /* length of bitfield        */  
    145.     __u32 msb_right;        /* != 0 : Most significant bit is */   
    146.                     /* right */   
    147. };  

    该函数主要将板级信息s3c2410fb_display复制到对应的地方,然后根据RGB的模式设置位域。

    4.3 fb_ops方法

    在驱动程序中,定义了fb_ops,如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static struct fb_ops s3c2410fb_ops = {  
    2.     .owner      = THIS_MODULE,  
    3.     .fb_check_var   = s3c2410fb_check_var,      /*检查变量的合法性*/  
    4.     .fb_set_par = s3c2410fb_set_par,            /*将参数写入LCD控制器,该函数由帧缓冲核心调用*/  
    5.     .fb_blank   = s3c2410fb_blank,              /*该方法支持显示消隐和去消隐*/  
    6.     .fb_setcolreg   = s3c2410fb_setcolreg,      /*设置颜色寄存器*/  
    7.     .fb_fillrect    = cfb_fillrect,             /*用像素行填充矩形框,通用库函数*/  
    8.     .fb_copyarea    = cfb_copyarea,             /*将屏幕的一个矩形区域复制到另一个区域,通用库函数*/  
    9.     .fb_imageblit   = cfb_imageblit,            /*显示一副图像,通用库函数*/  
    10. };  
    [cpp] view plain copy
     
    1. static struct fb_ops s3c2410fb_ops = {  
    2.     .owner      = THIS_MODULE,  
    3.     .fb_check_var   = s3c2410fb_check_var,      /*检查变量的合法性*/  
    4.     .fb_set_par = s3c2410fb_set_par,            /*将参数写入LCD控制器,该函数由帧缓冲核心调用*/  
    5.     .fb_blank   = s3c2410fb_blank,              /*该方法支持显示消隐和去消隐*/  
    6.     .fb_setcolreg   = s3c2410fb_setcolreg,      /*设置颜色寄存器*/  
    7.     .fb_fillrect    = cfb_fillrect,             /*用像素行填充矩形框,通用库函数*/  
    8.     .fb_copyarea    = cfb_copyarea,             /*将屏幕的一个矩形区域复制到另一个区域,通用库函数*/  
    9.     .fb_imageblit   = cfb_imageblit,            /*显示一副图像,通用库函数*/  
    10. };  


    其中s3c2410fb_check_var在4.2节中已经分析过了,最后三个方法是通用库函数,在这里不作分析。
    剩余三个也是驱动程序提供的,现在对这三个程序进行分析。

    4.3. 1 s3c2410fb_set_par

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* 
    2.  *      s3c2410fb_set_par - Alters the hardware state. 
    3.  *      @info: frame buffer structure that represents a single frame buffer 
    4.  *      根据var中的值设置LCD控制器的寄存器 
    5.  */  
    6. static int s3c2410fb_set_par(struct fb_info *info)  
    7. {  
    8.     struct fb_var_screeninfo *var = &info->var;  
    9.   
    10.     switch (var->bits_per_pixel) {  
    11.     case 32:  
    12.     case 16:  
    13.     case 12:  
    14.         info->fix.visual = FB_VISUAL_TRUECOLOR;  
    15.         break;  
    16.     case 1:  
    17.         info->fix.visual = FB_VISUAL_MONO01;  
    18.         break;  
    19.     default:  
    20.         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;  
    21.         break;  
    22.     }  
    23.   
    24.     info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; /* 320*16/8 = 640Bytes */  
    25.   
    26.     /* activate this new configuration */  
    27.   
    28.     s3c2410fb_activate_var(info);  
    29.     return 0;  
    30. }  
    [cpp] view plain copy
     
    1. /* 
    2.  *      s3c2410fb_set_par - Alters the hardware state. 
    3.  *      @info: frame buffer structure that represents a single frame buffer 
    4.  *      根据var中的值设置LCD控制器的寄存器 
    5.  */  
    6. static int s3c2410fb_set_par(struct fb_info *info)  
    7. {  
    8.     struct fb_var_screeninfo *var = &info->var;  
    9.   
    10.     switch (var->bits_per_pixel) {  
    11.     case 32:  
    12.     case 16:  
    13.     case 12:  
    14.         info->fix.visual = FB_VISUAL_TRUECOLOR;  
    15.         break;  
    16.     case 1:  
    17.         info->fix.visual = FB_VISUAL_MONO01;  
    18.         break;  
    19.     default:  
    20.         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;  
    21.         break;  
    22.     }  
    23.   
    24.     info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; /* 320*16/8 = 640Bytes */  
    25.   
    26.     /* activate this new configuration */  
    27.   
    28.     s3c2410fb_activate_var(info);  
    29.     return 0;  
    30. }  

    该函数根据像素的位数设置了视觉模式,本例为16为,使用真彩色。然后计算了每行的数据元素大小。共240行。

    然后调用了s3c2410fb_activate_var来设置控制器并激活LCD。

    s3c2410fb_activate_var函数如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* s3c2410fb_activate_var 
    2.  * 
    3.  * activate (set) the controller from the given framebuffer 
    4.  * information 
    5.  */  
    6. static void s3c2410fb_activate_var(struct fb_info *info)  
    7. {  
    8.     struct s3c2410fb_info *fbi = info->par;  
    9.     void __iomem *regs = fbi->io;  
    10.     int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT; /*regs.lcdcon1在s3c2410fb_check_var设置*/  
    11.     struct fb_var_screeninfo *var = &info->var;  
    12.     int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2;  
    13.   
    14.     dprintk("%s: var->xres  = %d ", __func__, var->xres);  
    15.     dprintk("%s: var->yres  = %d ", __func__, var->yres);  
    16.     dprintk("%s: var->bpp   = %d ", __func__, var->bits_per_pixel);  
    17.   
    18.     if (type == S3C2410_LCDCON1_TFT) {  
    19.         s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);/*根据var,计算出控制寄存器需要设置的值*/  
    20.         --clkdiv;  
    21.         if (clkdiv < 0)  
    22.             clkdiv = 0;  
    23.     } else {  
    24.         s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);  
    25.         if (clkdiv < 2)  
    26.             clkdiv = 2;  
    27.     }  
    28.   
    29.     fbi->regs.lcdcon1 |=  S3C2410_LCDCON1_CLKVAL(clkdiv);/*设置CLKVAL*/  
    30.   
    31.     /* write new registers */  
    32.   
    33.     dprintk("new register set: ");  
    34.     dprintk("lcdcon[1] = 0x%08lx ", fbi->regs.lcdcon1);  
    35.     dprintk("lcdcon[2] = 0x%08lx ", fbi->regs.lcdcon2);  
    36.     dprintk("lcdcon[3] = 0x%08lx ", fbi->regs.lcdcon3);  
    37.     dprintk("lcdcon[4] = 0x%08lx ", fbi->regs.lcdcon4);  
    38.     dprintk("lcdcon[5] = 0x%08lx ", fbi->regs.lcdcon5);  
    39.     /*把计算好的值填入LCD控制器中*/  
    40.     writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID,     
    41.         regs + S3C2410_LCDCON1);                        /*仍然禁止LCD*/  
    42.     writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);  
    43.     writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);  
    44.     writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);  
    45.     writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);  
    46.   
    47.     /* set lcd address pointers */  
    48.     s3c2410fb_set_lcdaddr(info);                        /*设置LCD帧缓冲起始地址*/  
    49.   
    50.     fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,  
    51.     writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);   /*使能LCD*/  
    52. }  
    [cpp] view plain copy
     
    1. /* s3c2410fb_activate_var 
    2.  * 
    3.  * activate (set) the controller from the given framebuffer 
    4.  * information 
    5.  */  
    6. static void s3c2410fb_activate_var(struct fb_info *info)  
    7. {  
    8.     struct s3c2410fb_info *fbi = info->par;  
    9.     void __iomem *regs = fbi->io;  
    10.     int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT; /*regs.lcdcon1在s3c2410fb_check_var设置*/  
    11.     struct fb_var_screeninfo *var = &info->var;  
    12.     int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2;  
    13.   
    14.     dprintk("%s: var->xres  = %d ", __func__, var->xres);  
    15.     dprintk("%s: var->yres  = %d ", __func__, var->yres);  
    16.     dprintk("%s: var->bpp   = %d ", __func__, var->bits_per_pixel);  
    17.   
    18.     if (type == S3C2410_LCDCON1_TFT) {  
    19.         s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);/*根据var,计算出控制寄存器需要设置的值*/  
    20.         --clkdiv;  
    21.         if (clkdiv < 0)  
    22.             clkdiv = 0;  
    23.     } else {  
    24.         s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);  
    25.         if (clkdiv < 2)  
    26.             clkdiv = 2;  
    27.     }  
    28.   
    29.     fbi->regs.lcdcon1 |=  S3C2410_LCDCON1_CLKVAL(clkdiv);/*设置CLKVAL*/  
    30.   
    31.     /* write new registers */  
    32.   
    33.     dprintk("new register set: ");  
    34.     dprintk("lcdcon[1] = 0x%08lx ", fbi->regs.lcdcon1);  
    35.     dprintk("lcdcon[2] = 0x%08lx ", fbi->regs.lcdcon2);  
    36.     dprintk("lcdcon[3] = 0x%08lx ", fbi->regs.lcdcon3);  
    37.     dprintk("lcdcon[4] = 0x%08lx ", fbi->regs.lcdcon4);  
    38.     dprintk("lcdcon[5] = 0x%08lx ", fbi->regs.lcdcon5);  
    39.     /*把计算好的值填入LCD控制器中*/  
    40.     writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID,     
    41.         regs + S3C2410_LCDCON1);                        /*仍然禁止LCD*/  
    42.     writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);  
    43.     writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);  
    44.     writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);  
    45.     writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);  
    46.   
    47.     /* set lcd address pointers */  
    48.     s3c2410fb_set_lcdaddr(info);                        /*设置LCD帧缓冲起始地址*/  
    49.   
    50.     fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,  
    51.     writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);   /*使能LCD*/  
    52. }  

    其中调用的三个函数如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,  
    2.                       unsigned long pixclk)  
    3. {  
    4.     unsigned long clk = clk_get_rate(fbi->clk);         /*获取当前时钟频率(Hz)*/  
    5.     unsigned long long div;  
    6.   
    7.     /* pixclk is in picoseconds, our clock is in Hz 
    8.      * 
    9.      * Hz -> picoseconds is / 10^-12 
    10.      */  
    11.   
    12.     div = (unsigned long long)clk * pixclk;  
    13.     div >>= 12;            /* div / 2^12 */  
    14.     do_div(div, 625 * 625UL * 625); /* div / 5^12 */  
    15.   
    16.     dprintk("pixclk %ld, divisor is %ld ", pixclk, (long)div);  
    17.     return div;  
    18. }  
    19.   
    20. /* s3c2410fb_calculate_tft_lcd_regs 
    21.  * 
    22.  * calculate register values from var settings 
    23.  */  
    24. static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info,  
    25.                          struct s3c2410fb_hw *regs)  
    26. {  
    27.     const struct s3c2410fb_info *fbi = info->par;  
    28.     const struct fb_var_screeninfo *var = &info->var;  
    29.   
    30.     switch (var->bits_per_pixel) {  
    31.     case 1:  
    32.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;  
    33.         break;  
    34.     case 2:  
    35.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;  
    36.         break;  
    37.     case 4:  
    38.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;  
    39.         break;  
    40.     case 8:  
    41.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;  
    42.         regs->lcdcon5 |= S3C2410_LCDCON5_BSWP |  
    43.                  S3C2410_LCDCON5_FRM565;  
    44.         regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP;  
    45.         break;  
    46.     case 16:  
    47.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;  
    48.         regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP;  
    49.         regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP;  
    50.         break;  
    51.     case 32:  
    52.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP;  
    53.         regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP |  
    54.                    S3C2410_LCDCON5_HWSWP |  
    55.                    S3C2410_LCDCON5_BPP24BL);  
    56.         break;  
    57.     default:  
    58.         /* invalid pixel depth */  
    59.         dev_err(fbi->dev, "invalid bpp %d ",  
    60.             var->bits_per_pixel);  
    61.     }  
    62.     /* update X/Y info */  
    63.     dprintk("setting vert: up=%d, low=%d, sync=%d ",  
    64.         var->upper_margin, var->lower_margin, var->vsync_len);  
    65.   
    66.     dprintk("setting horz: lft=%d, rt=%d, sync=%d ",  
    67.         var->left_margin, var->right_margin, var->hsync_len);  
    68.     /* 
    69.         所有时序参数必须减1,因为在公式中: 
    70.         Frame Rate = 1/ [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1) } x {(HSPW+1) + (HBPD +1) 
    71.         + (HFPD+1) + (HOZVAL + 1) } x { 2 x ( CLKVAL+1 ) / ( HCLK ) } ] 
    72.     */  
    73.     regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |  
    74.             S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |  
    75.             S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |  
    76.             S3C2410_LCDCON2_VSPW(var->vsync_len - 1);  
    77.   
    78.     regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |  
    79.             S3C2410_LCDCON3_HFPD(var->left_margin - 1) |  
    80.             S3C2410_LCDCON3_HOZVAL(var->xres - 1);  
    81.   
    82.     regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);  
    83. }  
    84.   
    85. /* s3c2410fb_set_lcdaddr 
    86.  * 
    87.  * initialise lcd controller address pointers 
    88.  */  
    89. static void s3c2410fb_set_lcdaddr(struct fb_info *info)  
    90. {  
    91.     unsigned long saddr1, saddr2, saddr3;  
    92.     struct s3c2410fb_info *fbi = info->par;  
    93.     void __iomem *regs = fbi->io;  
    94.   
    95.     saddr1  = info->fix.smem_start >> 1;   /*帧缓冲区起始地址*/  
    96.     saddr2  = info->fix.smem_start;            
    97.     saddr2 += info->fix.line_length * info->var.yres;  
    98.     saddr2 >>= 1;                         /*帧缓冲区结束地址*/  
    99.   
    100.     saddr3 = S3C2410_OFFSIZE(0) |  
    101.          S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff); /*offset = 0, pagewidth = 320*/  
    102.   
    103.     dprintk("LCDSADDR1 = 0x%08lx ", saddr1);  
    104.     dprintk("LCDSADDR2 = 0x%08lx ", saddr2);  
    105.     dprintk("LCDSADDR3 = 0x%08lx ", saddr3);  
    106.   
    107.     writel(saddr1, regs + S3C2410_LCDSADDR1);  
    108.     writel(saddr2, regs + S3C2410_LCDSADDR2);  
    109.     writel(saddr3, regs + S3C2410_LCDSADDR3);  
    110. }  
    [cpp] view plain copy
     
    1. static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,  
    2.                       unsigned long pixclk)  
    3. {  
    4.     unsigned long clk = clk_get_rate(fbi->clk);         /*获取当前时钟频率(Hz)*/  
    5.     unsigned long long div;  
    6.   
    7.     /* pixclk is in picoseconds, our clock is in Hz 
    8.      * 
    9.      * Hz -> picoseconds is / 10^-12 
    10.      */  
    11.   
    12.     div = (unsigned long long)clk * pixclk;  
    13.     div >>= 12;            /* div / 2^12 */  
    14.     do_div(div, 625 * 625UL * 625); /* div / 5^12 */  
    15.   
    16.     dprintk("pixclk %ld, divisor is %ld ", pixclk, (long)div);  
    17.     return div;  
    18. }  
    19.   
    20. /* s3c2410fb_calculate_tft_lcd_regs 
    21.  * 
    22.  * calculate register values from var settings 
    23.  */  
    24. static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info,  
    25.                          struct s3c2410fb_hw *regs)  
    26. {  
    27.     const struct s3c2410fb_info *fbi = info->par;  
    28.     const struct fb_var_screeninfo *var = &info->var;  
    29.   
    30.     switch (var->bits_per_pixel) {  
    31.     case 1:  
    32.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;  
    33.         break;  
    34.     case 2:  
    35.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;  
    36.         break;  
    37.     case 4:  
    38.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;  
    39.         break;  
    40.     case 8:  
    41.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;  
    42.         regs->lcdcon5 |= S3C2410_LCDCON5_BSWP |  
    43.                  S3C2410_LCDCON5_FRM565;  
    44.         regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP;  
    45.         break;  
    46.     case 16:  
    47.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;  
    48.         regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP;  
    49.         regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP;  
    50.         break;  
    51.     case 32:  
    52.         regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP;  
    53.         regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP |  
    54.                    S3C2410_LCDCON5_HWSWP |  
    55.                    S3C2410_LCDCON5_BPP24BL);  
    56.         break;  
    57.     default:  
    58.         /* invalid pixel depth */  
    59.         dev_err(fbi->dev, "invalid bpp %d ",  
    60.             var->bits_per_pixel);  
    61.     }  
    62.     /* update X/Y info */  
    63.     dprintk("setting vert: up=%d, low=%d, sync=%d ",  
    64.         var->upper_margin, var->lower_margin, var->vsync_len);  
    65.   
    66.     dprintk("setting horz: lft=%d, rt=%d, sync=%d ",  
    67.         var->left_margin, var->right_margin, var->hsync_len);  
    68.     /* 
    69.         所有时序参数必须减1,因为在公式中: 
    70.         Frame Rate = 1/ [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1) } x {(HSPW+1) + (HBPD +1) 
    71.         + (HFPD+1) + (HOZVAL + 1) } x { 2 x ( CLKVAL+1 ) / ( HCLK ) } ] 
    72.     */  
    73.     regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |  
    74.             S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |  
    75.             S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |  
    76.             S3C2410_LCDCON2_VSPW(var->vsync_len - 1);  
    77.   
    78.     regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |  
    79.             S3C2410_LCDCON3_HFPD(var->left_margin - 1) |  
    80.             S3C2410_LCDCON3_HOZVAL(var->xres - 1);  
    81.   
    82.     regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);  
    83. }  
    84.   
    85. /* s3c2410fb_set_lcdaddr 
    86.  * 
    87.  * initialise lcd controller address pointers 
    88.  */  
    89. static void s3c2410fb_set_lcdaddr(struct fb_info *info)  
    90. {  
    91.     unsigned long saddr1, saddr2, saddr3;  
    92.     struct s3c2410fb_info *fbi = info->par;  
    93.     void __iomem *regs = fbi->io;  
    94.   
    95.     saddr1  = info->fix.smem_start >> 1;   /*帧缓冲区起始地址*/  
    96.     saddr2  = info->fix.smem_start;            
    97.     saddr2 += info->fix.line_length * info->var.yres;  
    98.     saddr2 >>= 1;                         /*帧缓冲区结束地址*/  
    99.   
    100.     saddr3 = S3C2410_OFFSIZE(0) |  
    101.          S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff); /*offset = 0, pagewidth = 320*/  
    102.   
    103.     dprintk("LCDSADDR1 = 0x%08lx ", saddr1);  
    104.     dprintk("LCDSADDR2 = 0x%08lx ", saddr2);  
    105.     dprintk("LCDSADDR3 = 0x%08lx ", saddr3);  
    106.   
    107.     writel(saddr1, regs + S3C2410_LCDSADDR1);  
    108.     writel(saddr2, regs + S3C2410_LCDSADDR2);  
    109.     writel(saddr3, regs + S3C2410_LCDSADDR3);  
    110. }  

    s3c2410fb_calc_pixclk用于计算时钟频率。

    s3c2410fb_calculate_tft_lcd_regs设置了LCD的控制寄存器。

    s3c2410fb_set_lcdaddr设置了LCD的地址寄存器,该寄存器的设置请参考datasheet。

    4.3. 2 s3c2410fb_blank

    该方法完成消隐功能。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* 
    2.  *      s3c2410fb_blank 
    3.  *  @blank_mode: the blank mode we want. 
    4.  *  @info: frame buffer structure that represents a single frame buffer 
    5.  * 
    6.  *  Blank the screen if blank_mode != 0, else unblank. Return 0 if 
    7.  *  blanking succeeded, != 0 if un-/blanking failed due to e.g. a 
    8.  *  video mode which doesn't support it. Implements VESA suspend 
    9.  *  and powerdown modes on hardware that supports disabling hsync/vsync: 
    10.  * 
    11.  *  Returns negative errno on error, or zero on success. 
    12.  * 
    13.  */  
    14. static int s3c2410fb_blank(int blank_mode, struct fb_info *info)  
    15. {  
    16.     struct s3c2410fb_info *fbi = info->par;  
    17.     void __iomem *tpal_reg = fbi->io;  
    18.   
    19.     dprintk("blank(mode=%d, info=%p) ", blank_mode, info);  
    20.   
    21.     tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;  
    22.   
    23.     if (blank_mode == FB_BLANK_POWERDOWN) {    /*消隐*/  
    24.         s3c2410fb_lcd_enable(fbi, 0);        /*禁止LCD*/  
    25.     } else {  
    26.         s3c2410fb_lcd_enable(fbi, 1);        /*启动LCD*/  
    27.     }  
    28.   
    29.     if (blank_mode == FB_BLANK_UNBLANK)        /*去消隐*/  
    30.         writel(0x0, tpal_reg);                /*禁止temporary palette*/  
    31.     else {                                    /*消隐*/  
    32.         dprintk("setting TPAL to output 0x000000 ");  
    33.         writel(S3C2410_TPAL_EN, tpal_reg);    /*使能temporary palette,颜色为黑色*/  
    34.     }  
    35.   
    36.     return 0;  
    37. }  
    [cpp] view plain copy
     
    1. /* 
    2.  *      s3c2410fb_blank 
    3.  *  @blank_mode: the blank mode we want. 
    4.  *  @info: frame buffer structure that represents a single frame buffer 
    5.  * 
    6.  *  Blank the screen if blank_mode != 0, else unblank. Return 0 if 
    7.  *  blanking succeeded, != 0 if un-/blanking failed due to e.g. a 
    8.  *  video mode which doesn't support it. Implements VESA suspend 
    9.  *  and powerdown modes on hardware that supports disabling hsync/vsync: 
    10.  * 
    11.  *  Returns negative errno on error, or zero on success. 
    12.  * 
    13.  */  
    14. static int s3c2410fb_blank(int blank_mode, struct fb_info *info)  
    15. {  
    16.     struct s3c2410fb_info *fbi = info->par;  
    17.     void __iomem *tpal_reg = fbi->io;  
    18.   
    19.     dprintk("blank(mode=%d, info=%p) ", blank_mode, info);  
    20.   
    21.     tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;  
    22.   
    23.     if (blank_mode == FB_BLANK_POWERDOWN) {    /*消隐*/  
    24.         s3c2410fb_lcd_enable(fbi, 0);        /*禁止LCD*/  
    25.     } else {  
    26.         s3c2410fb_lcd_enable(fbi, 1);        /*启动LCD*/  
    27.     }  
    28.   
    29.     if (blank_mode == FB_BLANK_UNBLANK)        /*去消隐*/  
    30.         writel(0x0, tpal_reg);                /*禁止temporary palette*/  
    31.     else {                                    /*消隐*/  
    32.         dprintk("setting TPAL to output 0x000000 ");  
    33.         writel(S3C2410_TPAL_EN, tpal_reg);    /*使能temporary palette,颜色为黑色*/  
    34.     }  
    35.   
    36.     return 0;  
    37. }  

    在消隐时,屏幕将全黑。

    4.3.3 s3c2410fb_setcolreg

    该函数的功能用于设置LCD的调色板。调色板的概念请看我的转帖:LCD调色板

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static int s3c2410fb_setcolreg(unsigned regno,  
    2.                    unsigned red, unsigned green, unsigned blue,  
    3.                    unsigned transp, struct fb_info *info)  
    4. {  
    5.     struct s3c2410fb_info *fbi = info->par;    /*par指向s3c2410fb_info*/  
    6.     void __iomem *regs = fbi->io;  
    7.     unsigned int val;  
    8.   
    9.     /* dprintk("setcol: regno=%d, rgb=%d,%d,%d ", 
    10.            regno, red, green, blue); */  
    11.   
    12.     switch (info->fix.visual) {      
    13.     case FB_VISUAL_TRUECOLOR:    /*使用真彩色*/  
    14.         /* true-colour, use pseudo-palette */  
    15.   
    16.         if (regno < 16) {    /*16种颜色,为什么只用16种颜色???????????*/  
    17.             u32 *pal = info->pseudo_palette;  
    18.   
    19.             val  = chan_to_field(red,   &info->var.red);  
    20.             val |= chan_to_field(green, &info->var.green);  
    21.             val |= chan_to_field(blue,  &info->var.blue);  
    22.   
    23.             pal[regno] = val;    /*保存颜色值*/  
    24.         }  
    25.         break;  
    26.   
    27.     case FB_VISUAL_PSEUDOCOLOR:  
    28.         if (regno < 256) {  
    29.             /* currently assume RGB 5-6-5 mode */  
    30.   
    31.             val  = (red   >>  0) & 0xf800;  
    32.             val |= (green >>  5) & 0x07e0;  
    33.             val |= (blue  >> 11) & 0x001f;  
    34.   
    35.             writel(val, regs + S3C2410_TFTPAL(regno));  
    36.             schedule_palette_update(fbi, regno, val);  
    37.         }  
    38.   
    39.         break;  
    40.   
    41.     default:  
    42.         return 1;    /* unknown type */  
    43.     }  
    44.   
    45.     return 0;  
    46. }  
    47. /* from pxafb.c */  
    48. static inline unsigned int chan_to_field(unsigned int chan,  
    49.                      struct fb_bitfield *bf)  
    50. {      
    51.     /*下面用到的length和offset在s3c2410fb_check_var函数中设置*/  
    52.     chan &= 0xffff;                /*取低16位*/  
    53.     chan >>= 16 - bf->length;   /*取第length为到16位为有效位*/  
    54.     return chan << bf->offset;    /*移动到相应的位置。*/  
    55. }  
    [cpp] view plain copy
     
    1. static int s3c2410fb_setcolreg(unsigned regno,  
    2.                    unsigned red, unsigned green, unsigned blue,  
    3.                    unsigned transp, struct fb_info *info)  
    4. {  
    5.     struct s3c2410fb_info *fbi = info->par;    /*par指向s3c2410fb_info*/  
    6.     void __iomem *regs = fbi->io;  
    7.     unsigned int val;  
    8.   
    9.     /* dprintk("setcol: regno=%d, rgb=%d,%d,%d ", 
    10.            regno, red, green, blue); */  
    11.   
    12.     switch (info->fix.visual) {      
    13.     case FB_VISUAL_TRUECOLOR:    /*使用真彩色*/  
    14.         /* true-colour, use pseudo-palette */  
    15.   
    16.         if (regno < 16) {    /*16种颜色,为什么只用16种颜色???????????*/  
    17.             u32 *pal = info->pseudo_palette;  
    18.   
    19.             val  = chan_to_field(red,   &info->var.red);  
    20.             val |= chan_to_field(green, &info->var.green);  
    21.             val |= chan_to_field(blue,  &info->var.blue);  
    22.   
    23.             pal[regno] = val;    /*保存颜色值*/  
    24.         }  
    25.         break;  
    26.   
    27.     case FB_VISUAL_PSEUDOCOLOR:  
    28.         if (regno < 256) {  
    29.             /* currently assume RGB 5-6-5 mode */  
    30.   
    31.             val  = (red   >>  0) & 0xf800;  
    32.             val |= (green >>  5) & 0x07e0;  
    33.             val |= (blue  >> 11) & 0x001f;  
    34.   
    35.             writel(val, regs + S3C2410_TFTPAL(regno));  
    36.             schedule_palette_update(fbi, regno, val);  
    37.         }  
    38.   
    39.         break;  
    40.   
    41.     default:  
    42.         return 1;    /* unknown type */  
    43.     }  
    44.   
    45.     return 0;  
    46. }  
    47. /* from pxafb.c */  
    48. static inline unsigned int chan_to_field(unsigned int chan,  
    49.                      struct fb_bitfield *bf)  
    50. {      
    51.     /*下面用到的length和offset在s3c2410fb_check_var函数中设置*/  
    52.     chan &= 0xffff;                /*取低16位*/  
    53.     chan >>= 16 - bf->length;   /*取第length为到16位为有效位*/  
    54.     return chan << bf->offset;    /*移动到相应的位置。*/  
    55. }  

    我们使用的是真彩色,可以设置16种颜色,颜色的位域值通过调用chan_to_field获得,然后保存了颜色的值。但是比较奇怪的是,这里并没有将值保存到0x4d000400为起始的内存中,不知为何。 反而倒是在伪彩色模式下, 使用了writel(val, regs + S3C2410_TFTPAL(regno))写到内存中,然后调用schedule_palette_update函数来更新palette表。我们来看下。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static void schedule_palette_update(struct s3c2410fb_info *fbi,  
    2.                     unsigned int regno, unsigned int val)  
    3. {  
    4.     unsigned long flags;  
    5.     unsigned long irqen;  
    6.     void __iomem *irq_base = fbi->irq_base;  
    7.   
    8.     local_irq_save(flags);  
    9.   
    10.     fbi->palette_buffer[regno] = val;  
    11.   
    12.     if (!fbi->palette_ready) {  
    13.         fbi->palette_ready = 1;  
    14.   
    15.         /* enable IRQ */  
    16.         irqen = readl(irq_base + S3C24XX_LCDINTMSK);  
    17.         irqen &= ~S3C2410_LCDINT_FRSYNC;  
    18.         writel(irqen, irq_base + S3C24XX_LCDINTMSK);  
    19.     }  
    20.   
    21.     local_irq_restore(flags);  
    22. }  
    [cpp] view plain copy
     
    1. static void schedule_palette_update(struct s3c2410fb_info *fbi,  
    2.                     unsigned int regno, unsigned int val)  
    3. {  
    4.     unsigned long flags;  
    5.     unsigned long irqen;  
    6.     void __iomem *irq_base = fbi->irq_base;  
    7.   
    8.     local_irq_save(flags);  
    9.   
    10.     fbi->palette_buffer[regno] = val;  
    11.   
    12.     if (!fbi->palette_ready) {  
    13.         fbi->palette_ready = 1;  
    14.   
    15.         /* enable IRQ */  
    16.         irqen = readl(irq_base + S3C24XX_LCDINTMSK);  
    17.         irqen &= ~S3C2410_LCDINT_FRSYNC;  
    18.         writel(irqen, irq_base + S3C24XX_LCDINTMSK);  
    19.     }  
    20.   
    21.     local_irq_restore(flags);  
    22. }  

    这个函数的作用就是开启了LCD的帧同步中断,这个中断在VSYNC信号从无效变成有效时产生。当中断产生时,会调用在probe方法中注册的ISR。ISR如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)  
    2. {  
    3.     struct s3c2410fb_info *fbi = dev_id;  
    4.     void __iomem *irq_base = fbi->irq_base;  
    5.     unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);  
    6. b  
    7.     if (lcdirq & S3C2410_LCDINT_FRSYNC) {  
    8.         if (fbi->palette_ready)  
    9.             s3c2410fb_write_palette(fbi);  
    10.   
    11.         writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);  
    12.         writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);  
    13.     }  
    14.   
    15.     return IRQ_HANDLED;  
    16. }  
    17.   
    18. static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)  
    19. {  
    20.     unsigned int i;  
    21.     void __iomem *regs = fbi->io;  
    22.   
    23.     fbi->palette_ready = 0;  /*清除ready标志*/  
    24.   
    25.     for (i = 0; i < 256; i++) {  
    26.         unsigned long ent = fbi->palette_buffer[i];  
    27.         if (ent == PALETTE_BUFF_CLEAR)  
    28.             continue;  
    29.   
    30.         writel(ent, regs + S3C2410_TFTPAL(i));  
    31.   
    32.         /* it seems the only way to know exactly 
    33.          * if the palette wrote ok, is to check 
    34.          * to see if the value verifies ok 
    35.          */  
    36.   
    37.         if (readw(regs + S3C2410_TFTPAL(i)) == ent)  
    38.             fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR;  
    39.         else  
    40.             fbi->palette_ready = 1;   /* retry */  
    41.     }  
    42. }  
    [cpp] view plain copy
     
    1. static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)  
    2. {  
    3.     struct s3c2410fb_info *fbi = dev_id;  
    4.     void __iomem *irq_base = fbi->irq_base;  
    5.     unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);  
    6. b  
    7.     if (lcdirq & S3C2410_LCDINT_FRSYNC) {  
    8.         if (fbi->palette_ready)  
    9.             s3c2410fb_write_palette(fbi);  
    10.   
    11.         writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);  
    12.         writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);  
    13.     }  
    14.   
    15.     return IRQ_HANDLED;  
    16. }  
    17.   
    18. static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)  
    19. {  
    20.     unsigned int i;  
    21.     void __iomem *regs = fbi->io;  
    22.   
    23.     fbi->palette_ready = 0;  /*清除ready标志*/  
    24.   
    25.     for (i = 0; i < 256; i++) {  
    26.         unsigned long ent = fbi->palette_buffer[i];  
    27.         if (ent == PALETTE_BUFF_CLEAR)  
    28.             continue;  
    29.   
    30.         writel(ent, regs + S3C2410_TFTPAL(i));  
    31.   
    32.         /* it seems the only way to know exactly 
    33.          * if the palette wrote ok, is to check 
    34.          * to see if the value verifies ok 
    35.          */  
    36.   
    37.         if (readw(regs + S3C2410_TFTPAL(i)) == ent)  
    38.             fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR;  
    39.         else  
    40.             fbi->palette_ready = 1;   /* retry */  
    41.     }  
    42. }  

    在中断函数中调用了s3c2410fb_write_palette,该函数对写入内存的颜色值进行检查。如果确认其已经写入,则将palette_buffer中的清除,否则retry。

    5. 总结

    本文对frambuffer子系统做了简单的介绍。frambuffer子系统的函数相当之多,在这里是不可能一一介绍的。本文首先介绍了主要的数据结构,

    随后分析了frambuffer核心层,在核心层简单的分析了5个API函数,接着,对驱动层做了介绍,驱动层的大多数函数都给出了分析。

  • 相关阅读:
    session
    php增删改查,分页
    sql题
    php简单的数据增删改查
    php简单登录注册验证
    js题
    jQHTML(获取内容和属性)
    jQ效果(动画)
    Codeforces Round #460 (Div. 2): D. Substring(DAG+DP+判环)
    POJ 2891 中国剩余定理(不互素)
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7301057.html
Copyright © 2020-2023  润新知