Chinaunix首页 | 论坛 | 博客
  • 博客访问: 138867
  • 博文数量: 49
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 182
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-14 13:22
个人简介

Linux的热爱者

文章存档

2014年(7)

2013年(42)

我的朋友

分类: LINUX

2013-05-03 10:35:18

原文地址:lcd驱动层次分析 作者:rxlinux


点击(此处)折叠或打开

  1. 重要的数据结构
  2.    在linux字符设备驱动程序设计中,有3种非常重要的数据结构(这三种数据结构在\include\linux\Fs.h头文件中定义):

  3.    struct file
  4.    struct inode
  5.    struct file_operations
  6.    
  7.    struct file介绍
  8.      在内核中代表一个打开的文件。系统中每个打开的文件在内核空间都有一个关联的struct file.
  9.    它由内核在打开文件时创建,在文件关闭时释放。
  10.     
  11.    struct file {
  12.     /*
  13.      * fu_list becomes invalid after file_free is called and queued via
  14.      * fu_rcuhead for RCU freeing
  15.      */
  16.     union {
  17.         struct list_head    fu_list;
  18.         struct rcu_head     fu_rcuhead;
  19.     } f_u;
  20.     struct path        f_path;
  21. #define f_dentry    f_path.dentry
  22. #define f_vfsmnt    f_path.mnt
  23.     const struct file_operations    *f_op;
  24.     spinlock_t        f_lock; /* f_ep_links, f_flags, no IRQ */
  25. #ifdef CONFIG_SMP
  26.     int            f_sb_list_cpu;
  27. #endif
  28.     atomic_long_t        f_count;
  29.     unsigned int         f_flags;
  30.     fmode_t            f_mode;
  31.     loff_t            f_pos;
  32.     struct fown_struct    f_owner;
  33.     const struct cred    *f_cred;
  34.     struct file_ra_state    f_ra;

  35.     u64            f_version;
  36. #ifdef CONFIG_SECURITY
  37.     void            *f_security;
  38. #endif
  39.     /* needed for tty driver, and maybe others */
  40.     void            *private_data;

  41. #ifdef CONFIG_EPOLL
  42.     /* Used by fs/eventpoll.c to link all the hooks to this file */
  43.     struct list_head    f_ep_links;
  44. #endif /* #ifdef CONFIG_EPOLL */
  45.     struct address_space    *f_mapping;
  46. #ifdef CONFIG_DEBUG_WRITECOUNT
  47.     unsigned long f_mnt_write_state;
  48. #endif
  49. };

  50. 重要成员:
  51. loff_t            f_pos; //文件的读写位置
  52. const struct file_operations    *f_op;

  53. struct inode
  54.   用来记录文件的物理上的信息。因此,它和代表打开文件的file结构是不同的。一个文件可以对
  55. 应多个file结构,但只有一个inode结构。

  56.   struct inode {
  57.     /* RCU path lookup touches following: */
  58.     umode_t            i_mode;
  59.     uid_t            i_uid;
  60.     gid_t            i_gid;
  61.     const struct inode_operations    *i_op;
  62.     struct super_block    *i_sb;

  63.     spinlock_t        i_lock;    /* i_blocks, i_bytes, maybe i_size */
  64.     unsigned int        i_flags;
  65.     struct mutex        i_mutex;

  66.     unsigned long        i_state;
  67.     unsigned long        dirtied_when;    /* jiffies of first dirtying */

  68.     struct hlist_node    i_hash;
  69.     struct list_head    i_wb_list;    /* backing dev IO list */
  70.     struct list_head    i_lru;        /* inode LRU list */
  71.     struct list_head    i_sb_list;
  72.     union {
  73.         struct list_head    i_dentry;
  74.         struct rcu_head        i_rcu;
  75.     };
  76.     unsigned long        i_ino;
  77.     atomic_t        i_count;
  78.     unsigned int        i_nlink;
  79.     dev_t            i_rdev;
  80.     unsigned int        i_blkbits;
  81.     u64            i_version;
  82.     loff_t            i_size;
  83. #ifdef __NEED_I_SIZE_ORDERED
  84.     seqcount_t        i_size_seqcount;
  85. #endif
  86.     struct timespec        i_atime;
  87.     struct timespec        i_mtime;
  88.     struct timespec        i_ctime;
  89.     blkcnt_t        i_blocks;
  90.     unsigned short i_bytes;
  91.     struct rw_semaphore    i_alloc_sem;
  92.     const struct file_operations    *i_fop;    /* former ->i_op->default_file_ops */
  93.     struct file_lock    *i_flock;
  94.     struct address_space    *i_mapping;
  95.     struct address_space    i_data;
  96. #ifdef CONFIG_QUOTA
  97.     struct dquot        *i_dquot[MAXQUOTAS];
  98. #endif
  99.     struct list_head    i_devices;
  100.     union {
  101.         struct pipe_inode_info    *i_pipe;
  102.         struct block_device    *i_bdev;
  103.         struct cdev        *i_cdev;
  104.     };

  105.     __u32            i_generation;

  106. #ifdef CONFIG_FSNOTIFY
  107.     __u32            i_fsnotify_mask; /* all events this inode cares about */
  108.     struct hlist_head    i_fsnotify_marks;
  109. #endif

  110. #ifdef CONFIG_IMA
  111.     /* protected by i_lock */
  112.     unsigned int        i_readcount; /* struct files open RO */
  113. #endif
  114.     atomic_t        i_writecount;
  115. #ifdef CONFIG_SECURITY
  116.     void            *i_security;
  117. #endif
  118. #ifdef CONFIG_FS_POSIX_ACL
  119.     struct posix_acl    *i_acl;
  120.     struct posix_acl    *i_default_acl;
  121. #endif
  122.     void            *i_private; /* fs or device private pointer */
  123. };

  124. 重要成员:
  125.     dev_t            i_rdev; //设备号

  126. struct file_operations
  127.   一个函数指针的集合,定义能在设备上进行的操作。结构中的成员指向驱动中的函数,这些函数实现
  128. 一个特别的操作,对于不支持的操作保留为NULL。
  129. /*
  130.  * NOTE:
  131.  * all file operations except setlease can be called without
  132.  * the big kernel lock held in all filesystems.
  133.  */
  134. struct file_operations {
  135.     struct module *owner;
  136.     loff_t (*llseek) (struct file *, loff_t, int);
  137.     ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
  138.     ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
  139.     ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
  140.     ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
  141.     int (*readdir) (struct file *, void *, filldir_t);
  142.     unsigned int (*poll) (struct file *, struct poll_table_struct *);
  143.     long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
  144.     long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
  145.     int (*mmap) (struct file *, struct vm_area_struct *);
  146.     int (*open) (struct inode *, struct file *);
  147.     int (*flush) (struct file *, fl_owner_t id);
  148.     int (*release) (struct inode *, struct file *);
  149.     int (*fsync) (struct file *, int datasync);
  150.     int (*aio_fsync) (struct kiocb *, int datasync);
  151.     int (*fasync) (int, struct file *, int);
  152.     int (*lock) (struct file *, int, struct file_lock *);
  153.     ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
  154.     unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
  155.     int (*check_flags)(int);
  156.     int (*flock) (struct file *, int, struct file_lock *);
  157.     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
  158.     ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
  159.     int (*setlease)(struct file *, long, struct file_lock **);
  160.     long (*fallocate)(struct file *file, int mode, loff_t offset,
  161.              loff_t len);
  162. };
  163.   该操作函数定义了所有对文件支持的操作类型

  164. 以fbmem.c中具体的文件操作函数为例:

  165.   static const struct file_operations fb_fops = {
  166.     .owner =    THIS_MODULE,
  167.     .read =        fb_read,
  168.     .write =    fb_write,
  169.     .unlocked_ioctl = fb_ioctl,
  170. #ifdef CONFIG_COMPAT
  171.     .compat_ioctl = fb_compat_ioctl,
  172. #endif
  173.     .mmap =        fb_mmap,
  174.     .open =        fb_open,
  175.     .release =    fb_release,
  176. #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
  177.     .get_unmapped_area = get_fb_unmapped_area,
  178. #endif
  179. #ifdef CONFIG_FB_DEFERRED_IO
  180.     .fsync =    fb_deferred_io_fsync,
  181. #endif
  182.     .llseek =    default_llseek,
  183. };
  184. 左侧为函数指针,右侧为函数指针指向的函数名,例:app要使用open函数打开一个帧缓冲设备:

  185. 帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示卡,Linux 下还可支持多个帧缓冲设备,
  186. 最多可达 32 个,分别为/dev/fb0 到/dev/fb31,而/dev/fb 则为当前缺省的帧缓冲设备,通常指向/dev/fb0。
  187. 当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,次设备号则从0到31。
  188. 分别对应/dev/fb0-/dev/fb31。
  189. app:
  190.   fbfd = open("/dev/fb0", O_RDWR); //应用层打开一个主设备号为29次设备号为0的帧缓冲设备

  191. kernel:
  192.     fb_open
  193.     
  194.  fb_open(struct inode *inode, struct file *file)
  195. __acquires(&info->lock)
  196. __releases(&info->lock)
  197. {
  198.     int fbidx = iminor(inode);
  199.     struct fb_info *info;
  200.     int res = 0;

  201.     if (fbidx >= FB_MAX)
  202.         return -ENODEV;
  203.     info = registered_fb[fbidx];
  204.     if (!info)
  205.         request_module("fb%d", fbidx);
  206.     info = registered_fb[fbidx];
  207.     if (!info)
  208.         return -ENODEV;
  209.     mutex_lock(&info->lock);
  210.     if (!try_module_get(info->fbops->owner)) {
  211.         res = -ENODEV;
  212.         goto out;
  213.     }
  214.     file->private_data = info;
  215.     if (info->fbops->fb_open) {
  216.         res = info->fbops->fb_open(info,1);
  217.         if (res)
  218.             module_put(info->fbops->owner);
  219.     }
  220. #ifdef CONFIG_FB_DEFERRED_IO
  221.     if (info->fbdefio)
  222.         fb_deferred_io_open(info, inode, file);
  223. #endif
  224. out:
  225.     mutex_unlock(&info->lock);
  226.     return res;
  227. }
  228. 从前面知识知inode用来记录文件的物理上的信息,并有一个重要的参数(设备号(主次设备号)) dev_t        i_rdev;

  229.   分析这个open函数:
  230.     int fbidx = iminor(inode); //获取次设备号(因为帧缓冲设备主设备号定了都为29)
  231. iminor函数实际上就是获取i_rdev中的次设备号的
  232.   static inline unsigned iminor(const struct inode *inode)
  233. {
  234.     return MINOR(inode->i_rdev);
  235. }
  236. 获取到次设备号后
  237.   struct fb_info *info; //定义了一个fb_info结构体
  238. struct fb_info {
  239.     int node;
  240.     int flags;
  241.     struct mutex lock;        /* Lock for open/release/ioctl funcs */
  242.     struct mutex mm_lock;        /* Lock for fb_mmap and smem_* fields */
  243.     struct fb_var_screeninfo var;    /* Current var */
  244.     struct fb_fix_screeninfo fix;    /* Current fix */
  245.     struct fb_monspecs monspecs;    /* Current Monitor specs */
  246.     struct work_struct queue;    /* Framebuffer event queue */
  247.     struct fb_pixmap pixmap;    /* Image hardware mapper */
  248.     struct fb_pixmap sprite;    /* Cursor hardware mapper */
  249.     struct fb_cmap cmap;        /* Current cmap */
  250.     struct list_head modelist; /* mode list */
  251.     struct fb_videomode *mode;    /* current mode */

  252. #ifdef CONFIG_FB_BACKLIGHT
  253.     /* assigned backlight device */
  254.     /* set before framebuffer registration,
  255.      remove after unregister */
  256.     struct backlight_device *bl_dev;

  257.     /* Backlight level curve */
  258.     struct mutex bl_curve_mutex;    
  259.     u8 bl_curve[FB_BACKLIGHT_LEVELS];
  260. #endif
  261. #ifdef CONFIG_FB_DEFERRED_IO
  262.     struct delayed_work deferred_work;
  263.     struct fb_deferred_io *fbdefio;
  264. #endif

  265.     struct fb_ops *fbops;
  266.     struct device *device;        /* This is the parent */
  267.     struct device *dev;        /* This is this fb device */
  268.     int class_flag; /* private sysfs flags */
  269. #ifdef CONFIG_FB_TILEBLITTING
  270.     struct fb_tile_ops *tileops; /* Tile Blitting */
  271. #endif
  272.     char __iomem *screen_base;    /* Virtual address */
  273.     unsigned long screen_size;    /* Amount of ioremapped VRAM or 0 */
  274.     void *pseudo_palette;        /* Fake palette of 16 colors */
  275. #define FBINFO_STATE_RUNNING    0
  276. #define FBINFO_STATE_SUSPENDED    1
  277.     u32 state;            /* Hardware state i.e suspend */
  278.     void *fbcon_par; /* fbcon use-only private area */
  279.     /* From here on everything is device dependent */
  280.     void *par;
  281.     /* we need the PCI or similiar aperture base/size not
  282.      smem_start/size as smem_start may just be an object
  283.      allocated inside the aperture so may not actually overlap */
  284.     struct apertures_struct {
  285.         unsigned int count;
  286.         struct aperture {
  287.             resource_size_t base;
  288.             resource_size_t size;
  289.         } ranges[0];
  290.     } *apertures;
  291. };

  292. static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
  293.     struct apertures_struct *a = kzalloc(sizeof(struct apertures_struct)
  294.             + max_num * sizeof(struct aperture), GFP_KERNEL);
  295.     if (!a)
  296.         return NULL;
  297.     a->count = max_num;
  298.     return a;
  299. }

  300.  该结构体就是用来描述帧缓冲设备的,要结合具体的硬件来设置
  301.  继续:
  302.  info = registered_fb[fbidx];
  303.  FB_MAX是一个宏即为32,定义了数组的最大项
  304.  Linux 下还可支持多个帧缓冲设备,最多可达 32 个,分别为/dev/fb0 到/dev/fb31,
  305.  而/dev/fb 则为当前缺省的帧缓冲设备,通常指向/dev/fb0。
  306. 当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,
  307. 次设备号则从0到31。分别对应/dev/fb0-/dev/fb31。
  308.  应用层执行open函数打开/dev/fb0时
  309.  info = registered_fb[fbidx]; // 这里fbidx即为0
  310.  继续:即调用info结构体(fb_info类型)中的fbops(本身又是个结构体)中的fb_open(如果有的话)
  311.  if (info->fbops->fb_open) {
  312.         res = info->fbops->fb_open(info,1);
  313. 这样内核就完成了从应用层传来的open函数的操作。
  314.    同样
  315. app: read() //应用层想读这一个内存看看帧缓冲区有什么数据
  316. kernel: fb_read()
  317.   fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  318.   {
  319.     unsigned long p = *ppos;
  320.     struct inode *inode = file->f_path.dentry->d_inode;
  321.     int fbidx = iminor(inode); //获取次设备号
  322.     struct fb_info *info = registered_fb[fbidx]; //这里fbidx=0,即把registered_fb[0]给了info结构体
  323.     u8 *buffer, *dst;
  324.     u8 __iomem *src;
  325.     int c, cnt = 0, err = 0;
  326.     unsigned long total_size;

  327.     if (!info || ! info->screen_base)
  328.         return -ENODEV;

  329.     if (info->state != FBINFO_STATE_RUNNING)
  330.         return -EPERM;

  331.     if (info->fbops->fb_read)
  332.         return info->fbops->fb_read(info, buf, count, ppos); //如果有读函数就执行具体fb_read函数如果没有,程序继续执行:
  333.     
  334.     total_size = info->screen_size;

  335.     if (total_size == 0)
  336.         total_size = info->fix.smem_len;

  337.     if (p >= total_size)
  338.         return 0;

  339.     if (count >= total_size)
  340.         count = total_size;

  341.     if (count + p > total_size)
  342.         count = total_size - p;

  343.     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, //分配一个buffer
  344.              GFP_KERNEL);
  345.     if (!buffer)
  346.         return -ENOMEM;

  347.     src = (u8 __iomem *) (info->screen_base + p); //源地址 = 在info结构体填充的显存基地址加偏移量(即帧缓冲区)

  348.     if (info->fbops->fb_sync)
  349.         info->fbops->fb_sync(info);

  350.     while (count) {
  351.         c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  352.         dst = buffer;
  353.         fb_memcpy_fromfb(dst, src, c); //把帧缓冲区指定位置的数据先放到刚定义的dst地址里去(fb_memcpy_fromfb)
  354.         dst += c;
  355.         src += c;

  356.         if (copy_to_user(buf, buffer, c)) { //然后执行copy_to_user函数把数据从内核空间(buffer)传到用户空间(buf)
  357.             err = -EFAULT;
  358.             break;
  359.         }
  360.         *ppos += c;
  361.         buf += c;
  362.         cnt += c;
  363.         count -= c;
  364.     }

  365.     kfree(buffer);

  366.     return (err) ? err : cnt;
  367. }

  368. 上面的registered_fb[]数组是在register_framebuffer()里被设置,即在写lcd 的驱动时最终注册时会调用,具体如下:

  369. register_framebuffer(struct fb_info *fb_info)
  370. {
  371.     int i;
  372.     struct fb_event event;
  373.     struct fb_videomode mode;

  374.     if (num_registered_fb == FB_MAX)
  375.         return -ENXIO;

  376.     if (fb_check_foreignness(fb_info))
  377.         return -ENOSYS;

  378.     remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
  379.                      fb_is_primary_device(fb_info));

  380.     num_registered_fb++;
  381.     for (i = 0 ; i < FB_MAX; i++)
  382.         if (!registered_fb[i])
  383.             break;
  384.     fb_info->node = i;
  385.     mutex_init(&fb_info->lock);
  386.     mutex_init(&fb_info->mm_lock);

  387.     fb_info->dev = device_create(fb_class, fb_info->device,
  388.                  MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
  389.     if (IS_ERR(fb_info->dev)) {
  390.         /* Not fatal */
  391.         printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
  392.         fb_info->dev = NULL;
  393.     } else
  394.         fb_init_device(fb_info);

  395.     if (fb_info->pixmap.addr == NULL) {
  396.         fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
  397.         if (fb_info->pixmap.addr) {
  398.             fb_info->pixmap.size = FBPIXMAPSIZE;
  399.             fb_info->pixmap.buf_align = 1;
  400.             fb_info->pixmap.scan_align = 1;
  401.             fb_info->pixmap.access_align = 32;
  402.             fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
  403.         }
  404.     }    
  405.     fb_info->pixmap.offset = 0;

  406.     if (!fb_info->pixmap.blit_x)
  407.         fb_info->pixmap.blit_x = ~(u32)0;

  408.     if (!fb_info->pixmap.blit_y)
  409.         fb_info->pixmap.blit_y = ~(u32)0;

  410.     if (!fb_info->modelist.prev || !fb_info->modelist.next)
  411.         INIT_LIST_HEAD(&fb_info->modelist);

  412.     fb_var_to_videomode(&mode, &fb_info->var);
  413.     fb_add_videomode(&mode, &fb_info->modelist);
  414.     registered_fb[i] = fb_info; //完成了对数组的设置,这个数组里的每一项都是一个fb_info结构体

  415.     event.info = fb_info;
  416.     if (!lock_fb_info(fb_info))
  417.         return -ENODEV;
  418.     fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
  419.     unlock_fb_info(fb_info);
  420.     return 0;
  421. }

  422. 类似
  423. app: write() //应用程序想要往帧缓冲区里写数据,比如写入一幅图片的数据
  424. kernel: fb_write()

  425. fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  426. {
  427.     unsigned long p = *ppos;
  428.     struct inode *inode = file->f_path.dentry->d_inode;
  429.     int fbidx = iminor(inode); //获取次设备号
  430.     struct fb_info *info = registered_fb[fbidx]; //这里fbidx=0,即把registered_fb[0]给了info结构体
  431.     u8 *buffer, *src;
  432.     u8 __iomem *dst;
  433.     int c, cnt = 0, err = 0;
  434.     unsigned long total_size;

  435.     if (!info || !info->screen_base)
  436.         return -ENODEV;

  437.     if (info->state != FBINFO_STATE_RUNNING)
  438.         return -EPERM;

  439.     if (info->fbops->fb_write)
  440.         return info->fbops->fb_write(info, buf, count, ppos); //如果有写函数就执行具体fb_write函数如果没有,程序继续执行:
  441.     
  442.     total_size = info->screen_size;

  443.     if (total_size == 0)
  444.         total_size = info->fix.smem_len;

  445.     if (p > total_size)
  446.         return -EFBIG;

  447.     if (count > total_size) {
  448.         err = -EFBIG;
  449.         count = total_size;
  450.     }

  451.     if (count + p > total_size) {
  452.         if (!err)
  453.             err = -ENOSPC;

  454.         count = total_size - p;
  455.     }

  456.     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, //分配一个buffer
  457.              GFP_KERNEL);
  458.     if (!buffer)
  459.         return -ENOMEM;

  460.     dst = (u8 __iomem *) (info->screen_base + p); //目的地址 = 在info结构体填充的显存基地址加偏移量(即帧缓冲区)

  461.     if (info->fbops->fb_sync)
  462.         info->fbops->fb_sync(info);

  463.     while (count) {
  464.         c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  465.         src = buffer;

  466.         if (copy_from_user(src, buf, c)) { //然后执行copy_from_user函数把数据从用户空间(buf)传到内核空间(中转(src))
  467.             err = -EFAULT;
  468.             break;
  469.         }

  470.         fb_memcpy_tofb(dst, src, c); //最终把从用户空间传来的数据复制到帧缓冲区(dstfb_memcpy_tofb)专门和帧缓冲区打交道
  471.         dst += c;
  472.         src += c;
  473.         *ppos += c;
  474.         buf += c;
  475.         cnt += c;
  476.         count -= c;
  477.     }

  478.     kfree(buffer);

  479.     return (cnt) ? cnt : err;
  480. }

  481. 小结:fb_memcpy_tofb(),fb_memcpy_tofb()函数就像copy_from_user(),copy_to_user()函数一样,只不过前者负责在
  482. 帧缓冲区传递数据,无论是读还是写帧缓冲区即用户空间与内核空间传递数据时最终通过它来直接操作缓冲区。
  483.    但是使用read、write函数在读或写之前持续的寻址将会导致很多的开销。所以引入了映射屏幕内存的概念。
  484. 在我们可以映射屏幕内存之前,我们需要知道我们能映射多少,以及需要映射多少。第一件
  485. 要做的事情就是我们新得到的framebuffer设备取回信息,有两个结构包含着我们需要的信息,
  486. 第一个包含固定的屏幕信息,这部分是由硬件和驱动的能力决定的;第二个包含着可变的屏幕信息,
  487. 这部分是由硬件的当前状态决定的,可以由用户空间的程序调用ioctl()来改变。这两个信息在fb_info结构体里面设置的。


  488. 例:
  489. app:fbfd = open("/dev/fb0", O_RDWR);
  490.      ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo);
  491. kernel:
  492. static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  493. {
  494.     struct inode *inode = file->f_path.dentry->d_inode;
  495.     int fbidx = iminor(inode); //获得次设备号
  496.     struct fb_info *info = registered_fb[fbidx]; //这里fbidx=0,即把registered_fb[0]给了info结构体

  497.     return do_fb_ioctl(info, cmd, arg); //调用do_fb_ioctl函数
  498. }

  499. static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
  500.             unsigned long arg)
  501. {
  502.     struct fb_ops *fb;
  503.     struct fb_var_screeninfo var;
  504.     struct fb_fix_screeninfo fix;
  505.     struct fb_con2fbmap con2fb;
  506.     struct fb_cmap cmap_from;
  507.     struct fb_cmap_user cmap;
  508.     struct fb_event event;
  509.     void __user *argp = (void __user *)arg;
  510.     long ret = 0;

  511.     switch (cmd) {
  512.     case FBIOGET_VSCREENINFO: //用户空间要获取可变的屏幕信息
  513.         if (!lock_fb_info(info))
  514.             return -ENODEV;
  515.         var = info->var;
  516.         unlock_fb_info(info);

  517.         ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; //把可变的屏幕信息传到用户空间
  518.         break;
  519.     case FBIOPUT_VSCREENINFO: //用户空间要修改可变的信息
  520.         if (copy_from_user(&var, argp, sizeof(var))) //把从用户空间传来的信息传到内核空间
  521.             return -EFAULT;
  522.         if (!lock_fb_info(info))
  523.             return -ENODEV;
  524.         console_lock();
  525.         info->flags |= FBINFO_MISC_USEREVENT;
  526.         ret = fb_set_var(info, &var);
  527.         info->flags &= ~FBINFO_MISC_USEREVENT;
  528.         console_unlock();
  529.         unlock_fb_info(info);
  530.         if (!ret && copy_to_user(argp, &var, sizeof(var)))
  531.             ret = -EFAULT;
  532.         break;
  533.     case FBIOGET_FSCREENINFO: //用户空间要获取固定的屏幕信息
  534.         if (!lock_fb_info(info))
  535.             return -ENODEV;
  536.         fix = info->fix;
  537.         unlock_fb_info(info);

  538.         ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
  539.         break;
  540.     case FBIOPUTCMAP:
  541.         if (copy_from_user(&cmap, argp, sizeof(cmap)))
  542.             return -EFAULT;
  543.         ret = fb_set_user_cmap(&cmap, info);
  544.         break;
  545.     case FBIOGETCMAP:
  546.         if (copy_from_user(&cmap, argp, sizeof(cmap)))
  547.             return -EFAULT;
  548.         if (!lock_fb_info(info))
  549.             return -ENODEV;
  550.         cmap_from = info->cmap;
  551.         unlock_fb_info(info);
  552.         ret = fb_cmap_to_user(&cmap_from, &cmap);
  553.         break;
  554.     case FBIOPAN_DISPLAY:
  555.         if (copy_from_user(&var, argp, sizeof(var)))
  556.             return -EFAULT;
  557.         if (!lock_fb_info(info))
  558.             return -ENODEV;
  559.         console_lock();
  560.         ret = fb_pan_display(info, &var);
  561.         console_unlock();
  562.         unlock_fb_info(info);
  563.         if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
  564.             return -EFAULT;
  565.         break;
  566.     case FBIO_CURSOR:
  567.         ret = -EINVAL;
  568.         break;
  569.     case FBIOGET_CON2FBMAP:
  570.         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
  571.             return -EFAULT;
  572.         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
  573.             return -EINVAL;
  574.         con2fb.framebuffer = -1;
  575.         event.data = &con2fb;
  576.         if (!lock_fb_info(info))
  577.             return -ENODEV;
  578.         event.info = info;
  579.         fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
  580.         unlock_fb_info(info);
  581.         ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
  582.         break;
  583.     case FBIOPUT_CON2FBMAP:
  584.         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
  585.             return -EFAULT;
  586.         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
  587.             return -EINVAL;
  588.         if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
  589.             return -EINVAL;
  590.         if (!registered_fb[con2fb.framebuffer])
  591.             request_module("fb%d", con2fb.framebuffer);
  592.         if (!registered_fb[con2fb.framebuffer]) {
  593.             ret = -EINVAL;
  594.             break;
  595.         }
  596.         event.data = &con2fb;
  597.         if (!lock_fb_info(info))
  598.             return -ENODEV;
  599.         event.info = info;
  600.         ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
  601.         unlock_fb_info(info);
  602.         break;
  603.     case FBIOBLANK:
  604.         if (!lock_fb_info(info))
  605.             return -ENODEV;
  606.         console_lock();
  607.         info->flags |= FBINFO_MISC_USEREVENT;
  608.         ret = fb_blank(info, arg);
  609.         info->flags &= ~FBINFO_MISC_USEREVENT;
  610.         console_unlock();
  611.         unlock_fb_info(info);
  612.         break;
  613.     default:
  614.         if (!lock_fb_info(info))
  615.             return -ENODEV;
  616.         fb = info->fbops;
  617.         if (fb->fb_ioctl)
  618.             ret = fb->fb_ioctl(info, cmd, arg);
  619.         else
  620.             ret = -ENOTTY;
  621.         unlock_fb_info(info);
  622.     }
  623.     return ret;
  624. }

阅读(933) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:linux面试

给主人留下些什么吧!~~