4,436
社区成员
发帖
与我相关
我的任务
分享
struct fb_fix_screeninfo {
char id[16]; /* 设备名*/
unsigned long smem_start; /* frame buffer 缓冲区起始地址(物理地址)*/
__u32 smem_len; /* 缓冲区长度*/
__u32 type; /* 设备类型,例如TFT或STN*/
……
__u32 visual; /* 色彩类型,真彩色、假彩色或单色*/
……
__u32 line_length; /* 屏幕上每行的字节数 */
unsigned long mmio_start; /* IO映射区起始地址(物理地址) */
__u32 mmio_len; /* IO 映射区长度 */
__u32 accel; /* 指出使用的加速卡是哪些特定的芯片 */
__u16 reserved[3]; /* 系统保留*/
};
struct fb_var_screeninfo {
__u32 xres; /* visible resolution 可见分辨率 */
__u32 yres;
__u32 xres_virtual; /* virtual resolution 虚拟分辨率 */
__u32 yres_virtual;
__u32 xoffset; /* 从虚拟分辨率到可见分辨率的偏移量*/
__u32 yoffset;
__u32 bits_per_pixel; /* 像素深度 */
__u32 grayscale; /* 灰度级 */
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp; /* 透明度 */
__u32 nonstd; /* 非标准像素格式 */
……
__u32 pixclock; /* 像素时钟,单位是皮秒*/
__u32 left_margin; /* 左侧边缘区*/
__u32 right_margin; /*右侧边缘区 */
__u32 upper_margin; /*顶部边缘区 */
__u32 lower_margin;
__u32 hsync_len; /*水平扫描边缘区 */
__u32 vsync_len; /*垂直扫描边缘区 */
…….
};
struct fb_info {
int node; /* 设备节点 */
int flags;
struct fb_var_screeninfo var; /* 当前可变参数 */
struct fb_fix_screeninfo fix; /* 当前固定参数 */
struct fb_monspecs monspecs; /* 当前监视器特征 */
struct work_struct queue; /* 帧缓冲事件队列 */
struct fb_pixmap pixmap; /* 图象硬件映射变量 */
struct fb_pixmap sprite; /* 光标硬件映射变量 */
struct fb_cmap cmap; /* 当前颜色映射变量 */
struct list_head modelist; /* 模式列表*/
struct fb_videomode *mode; /* 当前模式*/
......
struct fb_ops *fbops; /* 该指针指向驱动函数集 */
……
struct device *dev; /* 代表此帧缓冲设备 */
……
char __iomem *screen_base; /* IO映射基址(虚地址) */
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
void *pseudo_palette; /* 调色板内存地址 */
……
};
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
int (*fb_set_par)(struct fb_info *info);
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
int fbidx = iminor(file->f_path.dentry->d_inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
unsigned long off;
unsigned long start;
u32 len;
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
if (!fb)
return -ENODEV;
if (fb->fb_mmap) { //意思是:如果驱动程序自带了mmap函数,那就用它自己的
int res;
lock_kernel(); //上大内核锁
res = fb->fb_mmap(info, vma); //调用驱动程序自己的mmap函数
unlock_kernel();
return res;
}
lock_kernel();
start = info->fix.smem_start; //注意,这里指向了设备的物理地址
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); //调整对齐后长度
if (off >= len) {
/* 对应于I/O端口统一编址的情况 */
off -= len;
if (info->var.accel_flags) {
unlock_kernel();
return -EINVAL;
}
start = info->fix.mmio_start;//当I/O端口统一编址时就使用端口的物理地址
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
}
unlock_kernel();
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len) //判断虚拟内存长度是否超越实际长度
return -EINVAL;
off += start;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* 本内存页作为IO之用,已经保留 */
vma->vm_flags |= VM_IO | VM_RESERVED;
fb_pgprotect(file, vma, off); //对帧缓冲的内存页进行标识,不要挪作它用
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot)) //实际的映射操作
return -EAGAIN;
return 0;
}
int
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{
int flags = info->flags;
int ret = 0;
…….
if (!info->fbops->fb_check_var) {
*var = info->var;
goto done;
}
ret = info->fbops->fb_check_var(var, info); //在这里对设备的诸多参数进行检查
if (ret)
goto done;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
struct fb_videomode mode;
……
info->var = *var;
if (info->fbops->fb_set_par) //如果驱动程序自带fb_set_par函数就使用它
info->fbops->fb_set_par(info); //这个函数设置例如控制寄存器等可变参数
fb_pan_display(info, &info->var);//硬件虚拟显示
fb_set_cmap(&info->cmap, info); //调色板设置
fb_var_to_videomode(&mode, &info->var);//把可变参数转为显示模式参数
......
}
}
}
done:
return ret;
}
static int
fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx]; //设备
struct fb_ops *fb = info->fbops; //设备函数指针
struct fb_var_screeninfo var; //可变参数
struct fb_fix_screeninfo fix; //固定参数
struct fb_con2fbmap con2fb;
struct fb_cmap_user cmap; //调色板
struct fb_event event;
void __user *argp = (void __user *)arg;
int i;
if (!fb)
return -ENODEV;
switch (cmd) {
case FBIOGET_VSCREENINFO:
return copy_to_user(argp, &info->var,
sizeof(var)) ? -EFAULT : 0;//这里是读取可变参数
case FBIOPUT_VSCREENINFO:
if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT; //尝试是否可以设置参数?
acquire_console_sem(); //控制台上锁
info->flags |= FBINFO_MISC_USEREVENT;
i = fb_set_var(info, &var); //设置可变参数
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem(); //解锁
if (i) return i;
if (copy_to_user(argp, &var, sizeof(var)))
return -EFAULT;
return 0;
case FBIOGET_FSCREENINFO:
return copy_to_user(argp, &info->fix, //读取固定参数
sizeof(fix)) ? -EFAULT : 0;
case FBIOPUTCMAP: //设置调色板参数
if (copy_from_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
return (fb_set_user_cmap(&cmap, info));
……
case FBIOBLANK:
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
i = fb_blank(info, arg); //关闭显示器
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
return i;
default:
if (fb->fb_ioctl == NULL) //如果存在自定义的fb_ioctl就使用它
return -EINVAL;
return fb->fb_ioctl(info, cmd, arg);
}
}