📄 omapfb_main.c
字号:
bpp = var->bits_per_pixel; if (plane->color_mode == OMAPFB_COLOR_RGB444) bpp = 16; switch (var->rotate) { case 0: case 180: xres_min = OMAPFB_PLANE_XRES_MIN; xres_max = panel->x_res; yres_min = OMAPFB_PLANE_YRES_MIN; yres_max = panel->y_res; if (cpu_is_omap15xx()) { var->xres = panel->x_res; var->yres = panel->y_res; } break; case 90: case 270: xres_min = OMAPFB_PLANE_YRES_MIN; xres_max = panel->y_res; yres_min = OMAPFB_PLANE_XRES_MIN; yres_max = panel->x_res; if (cpu_is_omap15xx()) { var->xres = panel->y_res; var->yres = panel->x_res; } break; default: return -EINVAL; } if (var->xres < xres_min) var->xres = xres_min; if (var->yres < yres_min) var->yres = yres_min; if (var->xres > xres_max) var->xres = xres_max; if (var->yres > yres_max) var->yres = yres_max; if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; max_frame_size = fbdev->mem_desc.region[plane->idx].size; line_size = var->xres_virtual * bpp / 8; if (line_size * var->yres_virtual > max_frame_size) { /* Try to keep yres_virtual first */ line_size = max_frame_size / var->yres_virtual; var->xres_virtual = line_size * 8 / bpp; if (var->xres_virtual < var->xres) { /* Still doesn't fit. Shrink yres_virtual too */ var->xres_virtual = var->xres; line_size = var->xres * bpp / 8; var->yres_virtual = max_frame_size / line_size; } /* Recheck this, as the virtual size changed. */ if (var->xres_virtual < var->xres) var->xres = var->xres_virtual; if (var->yres_virtual < var->yres) var->yres = var->yres_virtual; if (var->xres < xres_min || var->yres < yres_min) return -EINVAL; } if (var->xres + var->xoffset > var->xres_virtual) var->xoffset = var->xres_virtual - var->xres; if (var->yres + var->yoffset > var->yres_virtual) var->yoffset = var->yres_virtual - var->yres; line_size = var->xres * bpp / 8; if (plane->color_mode == OMAPFB_COLOR_RGB444) { var->red.offset = 8; var->red.length = 4; var->red.msb_right = 0; var->green.offset = 4; var->green.length = 4; var->green.msb_right = 0; var->blue.offset = 0; var->blue.length = 4; var->blue.msb_right = 0; } else { var->red.offset = 11; var->red.length = 5; var->red.msb_right = 0; var->green.offset = 5; var->green.length = 6; var->green.msb_right = 0; var->blue.offset = 0; var->blue.length = 5; var->blue.msb_right = 0; } var->height = -1; var->width = -1; var->grayscale = 0; /* pixclock in ps, the rest in pixclock */ var->pixclock = 10000000 / (panel->pixel_clock / 100); var->left_margin = panel->hfp; var->right_margin = panel->hbp; var->upper_margin = panel->vfp; var->lower_margin = panel->vbp; var->hsync_len = panel->hsw; var->vsync_len = panel->vsw; /* TODO: get these from panel->config */ var->vmode = FB_VMODE_NONINTERLACED; var->sync = 0; return 0;}/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */static void omapfb_rotate(struct fb_info *fbi, int rotate){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; omapfb_rqueue_lock(fbdev); if (cpu_is_omap15xx() && rotate != fbi->var.rotate) { struct fb_var_screeninfo *new_var = &fbdev->new_var; memcpy(new_var, &fbi->var, sizeof(*new_var)); new_var->rotate = rotate; if (set_fb_var(fbi, new_var) == 0 && memcmp(new_var, &fbi->var, sizeof(*new_var))) { memcpy(&fbi->var, new_var, sizeof(*new_var)); ctrl_change_mode(fbi); } } omapfb_rqueue_unlock(fbdev);}/* * Set new x,y offsets in the virtual display for the visible area and switch * to the new mode. */static int omapfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; int r = 0; omapfb_rqueue_lock(fbdev); if (var->xoffset != fbi->var.xoffset || var->yoffset != fbi->var.yoffset) { struct fb_var_screeninfo *new_var = &fbdev->new_var; memcpy(new_var, &fbi->var, sizeof(*new_var)); new_var->xoffset = var->xoffset; new_var->yoffset = var->yoffset; if (set_fb_var(fbi, new_var)) r = -EINVAL; else { memcpy(&fbi->var, new_var, sizeof(*new_var)); ctrl_change_mode(fbi); } } omapfb_rqueue_unlock(fbdev); return r;}/* Set mirror to vertical axis and switch to the new mode. */static int omapfb_mirror(struct fb_info *fbi, int mirror){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; int r = 0; omapfb_rqueue_lock(fbdev); mirror = mirror ? 1 : 0; if (cpu_is_omap15xx()) r = -EINVAL; else if (mirror != plane->info.mirror) { plane->info.mirror = mirror; r = ctrl_change_mode(fbi); } omapfb_rqueue_unlock(fbdev); return r;}/* * Check values in var, try to adjust them in case of out of bound values if * possible, or return error. */static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; int r; omapfb_rqueue_lock(fbdev); if (fbdev->ctrl->sync != NULL) fbdev->ctrl->sync(); r = set_fb_var(fbi, var); omapfb_rqueue_unlock(fbdev); return r;}/* * Switch to a new mode. The parameters for it has been check already by * omapfb_check_var. */static int omapfb_set_par(struct fb_info *fbi){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; int r = 0; omapfb_rqueue_lock(fbdev); set_fb_fix(fbi); r = ctrl_change_mode(fbi); omapfb_rqueue_unlock(fbdev); return r;}int omapfb_update_window_async(struct fb_info *fbi, struct omapfb_update_window *win, void (*callback)(void *), void *callback_data){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; struct fb_var_screeninfo *var; var = &fbi->var; if (win->x >= var->xres || win->y >= var->yres || win->out_x > var->xres || win->out_y >= var->yres) return -EINVAL; if (!fbdev->ctrl->update_window || fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) return -ENODEV; if (win->x + win->width >= var->xres) win->width = var->xres - win->x; if (win->y + win->height >= var->yres) win->height = var->yres - win->y; /* The out sizes should be cropped to the LCD size */ if (win->out_x + win->out_width > fbdev->panel->x_res) win->out_width = fbdev->panel->x_res - win->out_x; if (win->out_y + win->out_height > fbdev->panel->y_res) win->out_height = fbdev->panel->y_res - win->out_y; if (!win->width || !win->height || !win->out_width || !win->out_height) return 0; return fbdev->ctrl->update_window(fbi, win, callback, callback_data);}EXPORT_SYMBOL(omapfb_update_window_async);static int omapfb_update_win(struct fb_info *fbi, struct omapfb_update_window *win){ struct omapfb_plane_struct *plane = fbi->par; int ret; omapfb_rqueue_lock(plane->fbdev); ret = omapfb_update_window_async(fbi, win, NULL, NULL); omapfb_rqueue_unlock(plane->fbdev); return ret;}static int omapfb_update_full_screen(struct fb_info *fbi){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; struct omapfb_update_window win; int r; if (!fbdev->ctrl->update_window || fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) return -ENODEV; win.x = 0; win.y = 0; win.width = fbi->var.xres; win.height = fbi->var.yres; win.out_x = 0; win.out_y = 0; win.out_width = fbi->var.xres; win.out_height = fbi->var.yres; win.format = 0; omapfb_rqueue_lock(fbdev); r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL); omapfb_rqueue_unlock(fbdev); return r;}static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; struct lcd_panel *panel = fbdev->panel; struct omapfb_plane_info old_info; int r = 0; if (pi->pos_x + pi->out_width > panel->x_res || pi->pos_y + pi->out_height > panel->y_res) return -EINVAL; omapfb_rqueue_lock(fbdev); if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) { /* * This plane's memory was freed, can't enable it * until it's reallocated. */ r = -EINVAL; goto out; } old_info = plane->info; plane->info = *pi; if (pi->enabled) { r = ctrl_change_mode(fbi); if (r < 0) { plane->info = old_info; goto out; } } r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled); if (r < 0) { plane->info = old_info; goto out; }out: omapfb_rqueue_unlock(fbdev); return r;}static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi){ struct omapfb_plane_struct *plane = fbi->par; *pi = plane->info; return 0;}static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx]; size_t size; int r = 0; if (fbdev->ctrl->setup_mem == NULL) return -ENODEV; if (mi->type > OMAPFB_MEMTYPE_MAX) return -EINVAL; size = PAGE_ALIGN(mi->size); omapfb_rqueue_lock(fbdev); if (plane->info.enabled) { r = -EBUSY; goto out; } if (rg->size != size || rg->type != mi->type) { struct fb_var_screeninfo *new_var = &fbdev->new_var; unsigned long old_size = rg->size; u8 old_type = rg->type; unsigned long paddr; rg->size = size; rg->type = mi->type; /* * size == 0 is a special case, for which we * don't check / adjust the screen parameters. * This isn't a problem since the plane can't * be reenabled unless its size is > 0. */ if (old_size != size && size) { if (size) { memcpy(new_var, &fbi->var, sizeof(*new_var)); r = set_fb_var(fbi, new_var); if (r < 0) goto out; } } if (fbdev->ctrl->sync) fbdev->ctrl->sync(); r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr); if (r < 0) { /* Revert changes. */ rg->size = old_size; rg->type = old_type; goto out; } rg->paddr = paddr; if (old_size != size) { if (size) { memcpy(&fbi->var, new_var, sizeof(fbi->var)); set_fb_fix(fbi); } else { /* * Set these explicitly to indicate that the * plane memory is dealloce'd, the other * screen parameters in var / fix are invalid. */ fbi->fix.smem_start = 0; fbi->fix.smem_len = 0; } } }out: omapfb_rqueue_unlock(fbdev); return r;}static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi){ struct omapfb_plane_struct *plane = fbi->par; struct omapfb_device *fbdev = plane->fbdev; struct omapfb_mem_region *rg; rg = &fbdev->mem_desc.region[plane->idx]; memset(mi, 0, sizeof(*mi)); mi->size = rg->size; mi->type = rg->type; return 0;}static int omapfb_set_color_key(struct omapfb_device *fbdev, struct omapfb_color_key *ck){ int r; if (!fbdev->ctrl->set_color_key) return -ENODEV; omapfb_rqueue_lock(fbdev); r = fbdev->ctrl->set_color_key(ck); omapfb_rqueue_unlock(fbdev); return r;}static int omapfb_get_color_key(struct omapfb_device *fbdev, struct omapfb_color_key *ck){ int r; if (!fbdev->ctrl->get_color_key) return -ENODEV; omapfb_rqueue_lock(fbdev); r = fbdev->ctrl->get_color_key(ck); omapfb_rqueue_unlock(fbdev); return r;}static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];static int notifier_inited;static void omapfb_init_notifier(void){ int i; for (i = 0; i < OMAPFB_PLANE_NUM; i++) BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);}int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, omapfb_notifier_callback_t callback, void *callback_data){ int r; if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM) return -EINVAL; if (!notifier_inited) { omapfb_init_notifier(); notifier_inited = 1; } omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *, unsigned long, void *))callback; omapfb_nb->data = callback_data; r = blocking_notifier_chain_register(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -