1、open过程分析
fb_test.c
main.c
//默认打开/dev/fb0
fb_open(req_fb, &fb_info/*打开的信息保存在这里*/);
//传入的是0,所以打开的是/dev/fb0
sprintf(str, "/dev/fb%d", fb_num);
//根据主设备号29找到驱动程序,根据次设备号0,这个驱动程序的哪一个设备
fd = open(str, O_RDWR);//主设备号: 29, 次设备号: 0
--------------------------------------------------------------
kernel:
/********************fbmem.c*********************************/
.open = fb_open,
/*根据/dev/fb0得到这个设备节点的次设备号*/
int fbidx = iminor(inode);//fbidx=0
//跟硬件相关的结构体
struct fb_info *info;
//根据这个设备节点的次设备号fbidx获得一个struct fb_info结构体
info = get_fb_info(fbidx);
//次设备号为:fbidx = 0
//取出registered_fb“以次设备号为0”的一项:registered_fb[0]
fb_info = registered_fb[idx];
//如果这个info = register_fd[0]的fbops有fb_open函数时就调用fb_open
if (info->fbops->fb_open)
res = info->fbops->fb_open(info,1);
--------------------------------------------------------------
/*********************lcd_drv.c*****************************/
fb_info分析注册过程
//1.3 注册fb_info结构体,向fbmem.c注册fb_info结构体
register_framebuffer(myfb_info);
//调用fbmem.c的do_register_framebuffer
ret = do_register_framebuffer(fb_info);
//这里+1
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
//如果第i项没有设置就跳出来,这样就找出一个空项,后边就这是这一个
if (!registered_fb[i])
break;
fb_info->node = i;//此时i = 0
//执行到这里的时候,代表有真正的硬件设备了,
//于是在类下创建设备,使用mdev或者udev自动创建设备节点
fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
//根据上边找到的空项,将传进来的fb_info结构体,就是lcd—drv.c static struct fb_info *myfb_info;
//registered_fb[0] = lcd—drv.c 的[struct fb_info *myfb_info;]
registered_fb[i] = fb_info;
2、ioctl分析
fb_test.c
main.c
//默认打开/dev/fb0
fb_open(req_fb, &fb_info/*打开的信息保存在这里*/);
//传入的是0,所以打开的是/dev/fb0
sprintf(str, "/dev/fb%d", fb_num);
//根据主设备号29找到驱动程序,根据次设备号0,这个驱动程序的哪一个设备
fd = open(str, O_RDWR);//主设备号: 29, 次设备号: 0
//通过ioctl获得可变参数和固定参数
IOCTL1(fd, FBIOGET_VSCREENINFO, &fb_info->var);
IOCTL1(fd, FBIOGET_FSCREENINFO, &fb_info->fix);
---------------------------kernel:start-----------------------------------
kernel:
/********************fbmem.c*********************************/
static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
//根据文件句柄获得fb_info
struct fb_info *info = file_fb_info(file);
return do_fb_ioctl(info, cmd, arg);
case FBIOGET_VSCREENINFO://可变的屏幕参数
if (!lock_fb_info(info))
return -ENODEV;
var = info->var;//保存可变信息
unlock_fb_info(info);
//将var复制到用户空间
ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
break;
case FBIOGET_FSCREENINFO://固定的屏幕信息
if (!lock_fb_info(info))
return -ENODEV;
fix = info->fix;//保存固定信息
unlock_fb_info(info);
//将fix复制到用户空间
ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
break;
------------------------------kernel:end--------------------------------
//通过ioctl就可以获取驱动程序设置fb_info结构体
printf("fb res %dx%d virtual %dx%d, line_len %d, bpp %d\n",
fb_info->var.xres, fb_info->var.yres,
fb_info->var.xres_virtual, fb_info->var.yres_virtual,
fb_info->fix.line_length, fb_info->var.bits_per_pixel);
//映射显存,应用程序读写显存要是到它的地址,最终导致驱动程序的mmp被调用
void *ptr = mmap(0,
fb_info->var.yres_virtual * fb_info->fix.line_length,
PROT_WRITE | PROT_READ,
MAP_SHARED, fd, 0);
---------------------------kernel:start-----------------------------------
fb_mem.c :mmpd导致fb_mmap调用
int fb_mmap(struct file *file, struct vm_area_struct * vma)
//设置固定参数的时候start和len全部都设置了
start = info->fix.smem_start;
len = info->fix.smem_len;
//将显存的物理起始地址和长度映射给应用程序,如何映射的不需要关系
return vm_iomap_memory(vma, start, len);
------------------------------kernel:end--------------------------------
//这里是应用程序自己的显存地址,后边就可以用这个显存的虚拟地址进行绘制
fb_info->ptr = ptr;