- 重要的数据结构
- 在linux字符设备驱动程序设计中,有3种非常重要的数据结构(这三种数据结构在\include\linux\Fs.h头文件中定义):
-
- struct file
- struct inode
- struct file_operations
-
- struct file介绍
- 在内核中代表一个打开的文件。系统中每个打开的文件在内核空间都有一个关联的struct file.
- 它由内核在打开文件时创建,在文件关闭时释放。
-
- struct file {
- /*
- * fu_list becomes invalid after file_free is called and queued via
- * fu_rcuhead for RCU freeing
- */
- union {
- struct list_head fu_list;
- struct rcu_head fu_rcuhead;
- } f_u;
- struct path f_path;
- #define f_dentry f_path.dentry
- #define f_vfsmnt f_path.mnt
- const struct file_operations *f_op;
- spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */
- #ifdef CONFIG_SMP
- int f_sb_list_cpu;
- #endif
- atomic_long_t f_count;
- unsigned int f_flags;
- fmode_t f_mode;
- loff_t f_pos;
- struct fown_struct f_owner;
- const struct cred *f_cred;
- struct file_ra_state f_ra;
-
- u64 f_version;
- #ifdef CONFIG_SECURITY
- void *f_security;
- #endif
- /* needed for tty driver, and maybe others */
- void *private_data;
-
- #ifdef CONFIG_EPOLL
- /* Used by fs/eventpoll.c to link all the hooks to this file */
- struct list_head f_ep_links;
- #endif /* #ifdef CONFIG_EPOLL */
- struct address_space *f_mapping;
- #ifdef CONFIG_DEBUG_WRITECOUNT
- unsigned long f_mnt_write_state;
- #endif
- };
-
- 重要成员:
- loff_t f_pos; //文件的读写位置
- const struct file_operations *f_op;
-
- struct inode
- 用来记录文件的物理上的信息。因此,它和代表打开文件的file结构是不同的。一个文件可以对
- 应多个file结构,但只有一个inode结构。
-
- struct inode {
- /* RCU path lookup touches following: */
- umode_t i_mode;
- uid_t i_uid;
- gid_t i_gid;
- const struct inode_operations *i_op;
- struct super_block *i_sb;
-
- spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
- unsigned int i_flags;
- struct mutex i_mutex;
-
- unsigned long i_state;
- unsigned long dirtied_when; /* jiffies of first dirtying */
-
- struct hlist_node i_hash;
- struct list_head i_wb_list; /* backing dev IO list */
- struct list_head i_lru; /* inode LRU list */
- struct list_head i_sb_list;
- union {
- struct list_head i_dentry;
- struct rcu_head i_rcu;
- };
- unsigned long i_ino;
- atomic_t i_count;
- unsigned int i_nlink;
- dev_t i_rdev;
- unsigned int i_blkbits;
- u64 i_version;
- loff_t i_size;
- #ifdef __NEED_I_SIZE_ORDERED
- seqcount_t i_size_seqcount;
- #endif
- struct timespec i_atime;
- struct timespec i_mtime;
- struct timespec i_ctime;
- blkcnt_t i_blocks;
- unsigned short i_bytes;
- struct rw_semaphore i_alloc_sem;
- const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
- struct file_lock *i_flock;
- struct address_space *i_mapping;
- struct address_space i_data;
- #ifdef CONFIG_QUOTA
- struct dquot *i_dquot[MAXQUOTAS];
- #endif
- struct list_head i_devices;
- union {
- struct pipe_inode_info *i_pipe;
- struct block_device *i_bdev;
- struct cdev *i_cdev;
- };
-
- __u32 i_generation;
-
- #ifdef CONFIG_FSNOTIFY
- __u32 i_fsnotify_mask; /* all events this inode cares about */
- struct hlist_head i_fsnotify_marks;
- #endif
-
- #ifdef CONFIG_IMA
- /* protected by i_lock */
- unsigned int i_readcount; /* struct files open RO */
- #endif
- atomic_t i_writecount;
- #ifdef CONFIG_SECURITY
- void *i_security;
- #endif
- #ifdef CONFIG_FS_POSIX_ACL
- struct posix_acl *i_acl;
- struct posix_acl *i_default_acl;
- #endif
- void *i_private; /* fs or device private pointer */
- };
-
- 重要成员:
- dev_t i_rdev; //设备号
-
- struct file_operations
- 一个函数指针的集合,定义能在设备上进行的操作。结构中的成员指向驱动中的函数,这些函数实现
- 一个特别的操作,对于不支持的操作保留为NULL。
- /*
- * NOTE:
- * all file operations except setlease can be called without
- * the big kernel lock held in all filesystems.
- */
- struct file_operations {
- struct module *owner;
- loff_t (*llseek) (struct file *, loff_t, int);
- ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
- ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
- ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
- int (*readdir) (struct file *, void *, filldir_t);
- unsigned int (*poll) (struct file *, struct poll_table_struct *);
- long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
- long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
- int (*mmap) (struct file *, struct vm_area_struct *);
- int (*open) (struct inode *, struct file *);
- int (*flush) (struct file *, fl_owner_t id);
- int (*release) (struct inode *, struct file *);
- int (*fsync) (struct file *, int datasync);
- int (*aio_fsync) (struct kiocb *, int datasync);
- int (*fasync) (int, struct file *, int);
- int (*lock) (struct file *, int, struct file_lock *);
- ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
- unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
- int (*check_flags)(int);
- int (*flock) (struct file *, int, struct file_lock *);
- ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
- ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
- int (*setlease)(struct file *, long, struct file_lock **);
- long (*fallocate)(struct file *file, int mode, loff_t offset,
- loff_t len);
- };
- 该操作函数定义了所有对文件支持的操作类型
-
- 以fbmem.c中具体的文件操作函数为例:
-
- static const struct file_operations fb_fops = {
- .owner = THIS_MODULE,
- .read = fb_read,
- .write = fb_write,
- .unlocked_ioctl = fb_ioctl,
- #ifdef CONFIG_COMPAT
- .compat_ioctl = fb_compat_ioctl,
- #endif
- .mmap = fb_mmap,
- .open = fb_open,
- .release = fb_release,
- #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
- .get_unmapped_area = get_fb_unmapped_area,
- #endif
- #ifdef CONFIG_FB_DEFERRED_IO
- .fsync = fb_deferred_io_fsync,
- #endif
- .llseek = default_llseek,
- };
- 左侧为函数指针,右侧为函数指针指向的函数名,例:app要使用open函数打开一个帧缓冲设备:
-
- 帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示卡,Linux 下还可支持多个帧缓冲设备,
- 最多可达 32 个,分别为/dev/fb0 到/dev/fb31,而/dev/fb 则为当前缺省的帧缓冲设备,通常指向/dev/fb0。
- 当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,次设备号则从0到31。
- 分别对应/dev/fb0-/dev/fb31。
- app:
- fbfd = open("/dev/fb0", O_RDWR); //应用层打开一个主设备号为29次设备号为0的帧缓冲设备
-
- kernel:
- fb_open
-
- fb_open(struct inode *inode, struct file *file)
- __acquires(&info->lock)
- __releases(&info->lock)
- {
- int fbidx = iminor(inode);
- struct fb_info *info;
- int res = 0;
-
- if (fbidx >= FB_MAX)
- return -ENODEV;
- info = registered_fb[fbidx];
- if (!info)
- request_module("fb%d", fbidx);
- info = registered_fb[fbidx];
- if (!info)
- return -ENODEV;
- mutex_lock(&info->lock);
- if (!try_module_get(info->fbops->owner)) {
- res = -ENODEV;
- goto out;
- }
- file->private_data = info;
- if (info->fbops->fb_open) {
- res = info->fbops->fb_open(info,1);
- if (res)
- module_put(info->fbops->owner);
- }
- #ifdef CONFIG_FB_DEFERRED_IO
- if (info->fbdefio)
- fb_deferred_io_open(info, inode, file);
- #endif
- out:
- mutex_unlock(&info->lock);
- return res;
- }
- 从前面知识知inode用来记录文件的物理上的信息,并有一个重要的参数(设备号(主次设备号)) dev_t i_rdev;
-
- 分析这个open函数:
- int fbidx = iminor(inode); //获取次设备号(因为帧缓冲设备主设备号定了都为29)
- iminor函数实际上就是获取i_rdev中的次设备号的
- static inline unsigned iminor(const struct inode *inode)
- {
- return MINOR(inode->i_rdev);
- }
- 获取到次设备号后
- struct fb_info *info; //定义了一个fb_info结构体
- struct fb_info {
- int node;
- int flags;
- struct mutex lock; /* Lock for open/release/ioctl funcs */
- struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
- struct fb_var_screeninfo var; /* Current var */
- struct fb_fix_screeninfo fix; /* Current fix */
- struct fb_monspecs monspecs; /* Current Monitor specs */
- struct work_struct queue; /* Framebuffer event queue */
- struct fb_pixmap pixmap; /* Image hardware mapper */
- struct fb_pixmap sprite; /* Cursor hardware mapper */
- struct fb_cmap cmap; /* Current cmap */
- struct list_head modelist; /* mode list */
- struct fb_videomode *mode; /* current mode */
-
- #ifdef CONFIG_FB_BACKLIGHT
- /* assigned backlight device */
- /* set before framebuffer registration,
- remove after unregister */
- struct backlight_device *bl_dev;
-
- /* Backlight level curve */
- struct mutex bl_curve_mutex;
- u8 bl_curve[FB_BACKLIGHT_LEVELS];
- #endif
- #ifdef CONFIG_FB_DEFERRED_IO
- struct delayed_work deferred_work;
- struct fb_deferred_io *fbdefio;
- #endif
-
- struct fb_ops *fbops;
- struct device *device; /* This is the parent */
- struct device *dev; /* This is this fb device */
- int class_flag; /* private sysfs flags */
- #ifdef CONFIG_FB_TILEBLITTING
- struct fb_tile_ops *tileops; /* Tile Blitting */
- #endif
- char __iomem *screen_base; /* Virtual address */
- unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
- void *pseudo_palette; /* Fake palette of 16 colors */
- #define FBINFO_STATE_RUNNING 0
- #define FBINFO_STATE_SUSPENDED 1
- u32 state; /* Hardware state i.e suspend */
- void *fbcon_par; /* fbcon use-only private area */
- /* From here on everything is device dependent */
- void *par;
- /* we need the PCI or similiar aperture base/size not
- smem_start/size as smem_start may just be an object
- allocated inside the aperture so may not actually overlap */
- struct apertures_struct {
- unsigned int count;
- struct aperture {
- resource_size_t base;
- resource_size_t size;
- } ranges[0];
- } *apertures;
- };
-
- static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
- struct apertures_struct *a = kzalloc(sizeof(struct apertures_struct)
- + max_num * sizeof(struct aperture), GFP_KERNEL);
- if (!a)
- return NULL;
- a->count = max_num;
- return a;
- }
-
- 该结构体就是用来描述帧缓冲设备的,要结合具体的硬件来设置
- 继续:
- info = registered_fb[fbidx];
- FB_MAX是一个宏即为32,定义了数组的最大项
- Linux 下还可支持多个帧缓冲设备,最多可达 32 个,分别为/dev/fb0 到/dev/fb31,
- 而/dev/fb 则为当前缺省的帧缓冲设备,通常指向/dev/fb0。
- 当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,
- 次设备号则从0到31。分别对应/dev/fb0-/dev/fb31。
- 应用层执行open函数打开/dev/fb0时
- info = registered_fb[fbidx]; // 这里fbidx即为0
- 继续:即调用info结构体(fb_info类型)中的fbops(本身又是个结构体)中的fb_open(如果有的话)
- if (info->fbops->fb_open) {
- res = info->fbops->fb_open(info,1);
- 这样内核就完成了从应用层传来的open函数的操作。
- 同样
- app: read() //应用层想读这一个内存看看帧缓冲区有什么数据
- kernel: fb_read()
- fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
- {
- unsigned long p = *ppos;
- struct inode *inode = file->f_path.dentry->d_inode;
- int fbidx = iminor(inode); //获取次设备号
- struct fb_info *info = registered_fb[fbidx]; //这里fbidx=0,即把registered_fb[0]给了info结构体
- u8 *buffer, *dst;
- u8 __iomem *src;
- int c, cnt = 0, err = 0;
- unsigned long total_size;
-
- if (!info || ! info->screen_base)
- return -ENODEV;
-
- if (info->state != FBINFO_STATE_RUNNING)
- return -EPERM;
-
- if (info->fbops->fb_read)
- return info->fbops->fb_read(info, buf, count, ppos); //如果有读函数就执行具体fb_read函数如果没有,程序继续执行:
-
- total_size = info->screen_size;
-
- if (total_size == 0)
- total_size = info->fix.smem_len;
-
- if (p >= total_size)
- return 0;
-
- if (count >= total_size)
- count = total_size;
-
- if (count + p > total_size)
- count = total_size - p;
-
- buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, //分配一个buffer
- GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- src = (u8 __iomem *) (info->screen_base + p); //源地址 = 在info结构体填充的显存基地址加偏移量(即帧缓冲区)
-
- if (info->fbops->fb_sync)
- info->fbops->fb_sync(info);
-
- while (count) {
- c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
- dst = buffer;
- fb_memcpy_fromfb(dst, src, c); //把帧缓冲区指定位置的数据先放到刚定义的dst地址里去(fb_memcpy_fromfb)
- dst += c;
- src += c;
-
- if (copy_to_user(buf, buffer, c)) { //然后执行copy_to_user函数把数据从内核空间(buffer)传到用户空间(buf)
- err = -EFAULT;
- break;
- }
- *ppos += c;
- buf += c;
- cnt += c;
- count -= c;
- }
-
- kfree(buffer);
-
- return (err) ? err : cnt;
- }
-
- 上面的registered_fb[]数组是在register_framebuffer()里被设置,即在写lcd 的驱动时最终注册时会调用,具体如下:
-
- register_framebuffer(struct fb_info *fb_info)
- {
- int i;
- struct fb_event event;
- struct fb_videomode mode;
-
- if (num_registered_fb == FB_MAX)
- return -ENXIO;
-
- if (fb_check_foreignness(fb_info))
- return -ENOSYS;
-
- remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
- fb_is_primary_device(fb_info));
-
- num_registered_fb++;
- for (i = 0 ; i < FB_MAX; i++)
- if (!registered_fb[i])
- break;
- fb_info->node = i;
- mutex_init(&fb_info->lock);
- mutex_init(&fb_info->mm_lock);
-
- fb_info->dev = device_create(fb_class, fb_info->device,
- MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
- if (IS_ERR(fb_info->dev)) {
- /* Not fatal */
- printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
- fb_info->dev = NULL;
- } else
- fb_init_device(fb_info);
-
- if (fb_info->pixmap.addr == NULL) {
- fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
- if (fb_info->pixmap.addr) {
- fb_info->pixmap.size = FBPIXMAPSIZE;
- fb_info->pixmap.buf_align = 1;
- fb_info->pixmap.scan_align = 1;
- fb_info->pixmap.access_align = 32;
- fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
- }
- }
- fb_info->pixmap.offset = 0;
-
- if (!fb_info->pixmap.blit_x)
- fb_info->pixmap.blit_x = ~(u32)0;
-
- if (!fb_info->pixmap.blit_y)
- fb_info->pixmap.blit_y = ~(u32)0;
-
- if (!fb_info->modelist.prev || !fb_info->modelist.next)
- INIT_LIST_HEAD(&fb_info->modelist);
-
- fb_var_to_videomode(&mode, &fb_info->var);
- fb_add_videomode(&mode, &fb_info->modelist);
- registered_fb[i] = fb_info; //完成了对数组的设置,这个数组里的每一项都是一个fb_info结构体
-
- event.info = fb_info;
- if (!lock_fb_info(fb_info))
- return -ENODEV;
- fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
- unlock_fb_info(fb_info);
- return 0;
- }
-
- 类似
- app: write() //应用程序想要往帧缓冲区里写数据,比如写入一幅图片的数据
- kernel: fb_write()
-
- fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
- {
- unsigned long p = *ppos;
- struct inode *inode = file->f_path.dentry->d_inode;
- int fbidx = iminor(inode); //获取次设备号
- struct fb_info *info = registered_fb[fbidx]; //这里fbidx=0,即把registered_fb[0]给了info结构体
- u8 *buffer, *src;
- u8 __iomem *dst;
- int c, cnt = 0, err = 0;
- unsigned long total_size;
-
- if (!info || !info->screen_base)
- return -ENODEV;
-
- if (info->state != FBINFO_STATE_RUNNING)
- return -EPERM;
-
- if (info->fbops->fb_write)
- return info->fbops->fb_write(info, buf, count, ppos); //如果有写函数就执行具体fb_write函数如果没有,程序继续执行:
-
- total_size = info->screen_size;
-
- if (total_size == 0)
- total_size = info->fix.smem_len;
-
- if (p > total_size)
- return -EFBIG;
-
- if (count > total_size) {
- err = -EFBIG;
- count = total_size;
- }
-
- if (count + p > total_size) {
- if (!err)
- err = -ENOSPC;
-
- count = total_size - p;
- }
-
- buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, //分配一个buffer
- GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- dst = (u8 __iomem *) (info->screen_base + p); //目的地址 = 在info结构体填充的显存基地址加偏移量(即帧缓冲区)
-
- if (info->fbops->fb_sync)
- info->fbops->fb_sync(info);
-
- while (count) {
- c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
- src = buffer;
-
- if (copy_from_user(src, buf, c)) { //然后执行copy_from_user函数把数据从用户空间(buf)传到内核空间(中转(src))
- err = -EFAULT;
- break;
- }
-
- fb_memcpy_tofb(dst, src, c); //最终把从用户空间传来的数据复制到帧缓冲区(dstfb_memcpy_tofb)专门和帧缓冲区打交道
- dst += c;
- src += c;
- *ppos += c;
- buf += c;
- cnt += c;
- count -= c;
- }
-
- kfree(buffer);
-
- return (cnt) ? cnt : err;
- }
-
- 小结:fb_memcpy_tofb(),fb_memcpy_tofb()函数就像copy_from_user(),copy_to_user()函数一样,只不过前者负责在
- 帧缓冲区传递数据,无论是读还是写帧缓冲区即用户空间与内核空间传递数据时最终通过它来直接操作缓冲区。
- 但是使用read、write函数在读或写之前持续的寻址将会导致很多的开销。所以引入了映射屏幕内存的概念。
- 在我们可以映射屏幕内存之前,我们需要知道我们能映射多少,以及需要映射多少。第一件
- 要做的事情就是我们新得到的framebuffer设备取回信息,有两个结构包含着我们需要的信息,
- 第一个包含固定的屏幕信息,这部分是由硬件和驱动的能力决定的;第二个包含着可变的屏幕信息,
- 这部分是由硬件的当前状态决定的,可以由用户空间的程序调用ioctl()来改变。这两个信息在fb_info结构体里面设置的。
-
-
- 例:
- app:fbfd = open("/dev/fb0", O_RDWR);
- ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo);
- kernel:
- static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- struct inode *inode = file->f_path.dentry->d_inode;
- int fbidx = iminor(inode); //获得次设备号
- struct fb_info *info = registered_fb[fbidx]; //这里fbidx=0,即把registered_fb[0]给了info结构体
-
- return do_fb_ioctl(info, cmd, arg); //调用do_fb_ioctl函数
- }
-
- static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
- {
- struct fb_ops *fb;
- struct fb_var_screeninfo var;
- struct fb_fix_screeninfo fix;
- struct fb_con2fbmap con2fb;
- struct fb_cmap cmap_from;
- struct fb_cmap_user cmap;
- struct fb_event event;
- void __user *argp = (void __user *)arg;
- long ret = 0;
-
- switch (cmd) {
- case FBIOGET_VSCREENINFO: //用户空间要获取可变的屏幕信息
- if (!lock_fb_info(info))
- return -ENODEV;
- var = info->var;
- unlock_fb_info(info);
-
- ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; //把可变的屏幕信息传到用户空间
- break;
- case FBIOPUT_VSCREENINFO: //用户空间要修改可变的信息
- if (copy_from_user(&var, argp, sizeof(var))) //把从用户空间传来的信息传到内核空间
- return -EFAULT;
- if (!lock_fb_info(info))
- return -ENODEV;
- console_lock();
- info->flags |= FBINFO_MISC_USEREVENT;
- ret = fb_set_var(info, &var);
- info->flags &= ~FBINFO_MISC_USEREVENT;
- console_unlock();
- unlock_fb_info(info);
- if (!ret && copy_to_user(argp, &var, sizeof(var)))
- ret = -EFAULT;
- break;
- case FBIOGET_FSCREENINFO: //用户空间要获取固定的屏幕信息
- if (!lock_fb_info(info))
- return -ENODEV;
- fix = info->fix;
- unlock_fb_info(info);
-
- ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
- break;
- case FBIOPUTCMAP:
- if (copy_from_user(&cmap, argp, sizeof(cmap)))
- return -EFAULT;
- ret = fb_set_user_cmap(&cmap, info);
- break;
- case FBIOGETCMAP:
- if (copy_from_user(&cmap, argp, sizeof(cmap)))
- return -EFAULT;
- if (!lock_fb_info(info))
- return -ENODEV;
- cmap_from = info->cmap;
- unlock_fb_info(info);
- ret = fb_cmap_to_user(&cmap_from, &cmap);
- break;
- case FBIOPAN_DISPLAY:
- if (copy_from_user(&var, argp, sizeof(var)))
- return -EFAULT;
- if (!lock_fb_info(info))
- return -ENODEV;
- console_lock();
- ret = fb_pan_display(info, &var);
- console_unlock();
- unlock_fb_info(info);
- if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
- return -EFAULT;
- break;
- case FBIO_CURSOR:
- ret = -EINVAL;
- break;
- case FBIOGET_CON2FBMAP:
- if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
- return -EFAULT;
- if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
- return -EINVAL;
- con2fb.framebuffer = -1;
- event.data = &con2fb;
- if (!lock_fb_info(info))
- return -ENODEV;
- event.info = info;
- fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
- unlock_fb_info(info);
- ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
- break;
- case FBIOPUT_CON2FBMAP:
- if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
- return -EFAULT;
- if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
- return -EINVAL;
- if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
- return -EINVAL;
- if (!registered_fb[con2fb.framebuffer])
- request_module("fb%d", con2fb.framebuffer);
- if (!registered_fb[con2fb.framebuffer]) {
- ret = -EINVAL;
- break;
- }
- event.data = &con2fb;
- if (!lock_fb_info(info))
- return -ENODEV;
- event.info = info;
- ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
- unlock_fb_info(info);
- break;
- case FBIOBLANK:
- if (!lock_fb_info(info))
- return -ENODEV;
- console_lock();
- info->flags |= FBINFO_MISC_USEREVENT;
- ret = fb_blank(info, arg);
- info->flags &= ~FBINFO_MISC_USEREVENT;
- console_unlock();
- unlock_fb_info(info);
- break;
- default:
- if (!lock_fb_info(info))
- return -ENODEV;
- fb = info->fbops;
- if (fb->fb_ioctl)
- ret = fb->fb_ioctl(info, cmd, arg);
- else
- ret = -ENOTTY;
- unlock_fb_info(info);
- }
- return ret;
- }
lcd驱动层次分析
最新推荐文章于 2021-06-06 21:59:42 发布