18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * vivid-osd.c - osd support for testing overlays. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/sched.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/font.h> 158c2ecf20Sopenharmony_ci#include <linux/mutex.h> 168c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 178c2ecf20Sopenharmony_ci#include <linux/kthread.h> 188c2ecf20Sopenharmony_ci#include <linux/freezer.h> 198c2ecf20Sopenharmony_ci#include <linux/fb.h> 208c2ecf20Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 238c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 248c2ecf20Sopenharmony_ci#include <media/v4l2-fh.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 268c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "vivid-core.h" 298c2ecf20Sopenharmony_ci#include "vivid-osd.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define MAX_OSD_WIDTH 720 328c2ecf20Sopenharmony_ci#define MAX_OSD_HEIGHT 576 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * Order: white, yellow, cyan, green, magenta, red, blue, black, 368c2ecf20Sopenharmony_ci * and same again with the alpha bit set (if any) 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistatic const u16 rgb555[16] = { 398c2ecf20Sopenharmony_ci 0x7fff, 0x7fe0, 0x03ff, 0x03e0, 0x7c1f, 0x7c00, 0x001f, 0x0000, 408c2ecf20Sopenharmony_ci 0xffff, 0xffe0, 0x83ff, 0x83e0, 0xfc1f, 0xfc00, 0x801f, 0x8000 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic const u16 rgb565[16] = { 448c2ecf20Sopenharmony_ci 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000, 458c2ecf20Sopenharmony_ci 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_civoid vivid_clear_fb(struct vivid_dev *dev) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci void *p = dev->video_vbase; 518c2ecf20Sopenharmony_ci const u16 *rgb = rgb555; 528c2ecf20Sopenharmony_ci unsigned x, y; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (dev->fb_defined.green.length == 6) 558c2ecf20Sopenharmony_ci rgb = rgb565; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci for (y = 0; y < dev->display_height; y++) { 588c2ecf20Sopenharmony_ci u16 *d = p; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci for (x = 0; x < dev->display_width; x++) 618c2ecf20Sopenharmony_ci d[x] = rgb[(y / 16 + x / 16) % 16]; 628c2ecf20Sopenharmony_ci p += dev->display_byte_stride; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct vivid_dev *dev = (struct vivid_dev *)info->par; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci switch (cmd) { 738c2ecf20Sopenharmony_ci case FBIOGET_VBLANK: { 748c2ecf20Sopenharmony_ci struct fb_vblank vblank; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci memset(&vblank, 0, sizeof(vblank)); 778c2ecf20Sopenharmony_ci vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT | 788c2ecf20Sopenharmony_ci FB_VBLANK_HAVE_VSYNC; 798c2ecf20Sopenharmony_ci vblank.count = 0; 808c2ecf20Sopenharmony_ci vblank.vcount = 0; 818c2ecf20Sopenharmony_ci vblank.hcount = 0; 828c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) 838c2ecf20Sopenharmony_ci return -EFAULT; 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci default: 888c2ecf20Sopenharmony_ci dprintk(dev, 1, "Unknown ioctl %08x\n", cmd); 898c2ecf20Sopenharmony_ci return -EINVAL; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* Framebuffer device handling */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int vivid_fb_set_var(struct vivid_dev *dev, struct fb_var_screeninfo *var) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci dprintk(dev, 1, "vivid_fb_set_var\n"); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (var->bits_per_pixel != 16) { 1018c2ecf20Sopenharmony_ci dprintk(dev, 1, "vivid_fb_set_var - Invalid bpp\n"); 1028c2ecf20Sopenharmony_ci return -EINVAL; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci dev->display_byte_stride = var->xres * dev->bytes_per_pixel; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci dprintk(dev, 1, "vivid_fb_get_fix\n"); 1128c2ecf20Sopenharmony_ci memset(fix, 0, sizeof(struct fb_fix_screeninfo)); 1138c2ecf20Sopenharmony_ci strscpy(fix->id, "vioverlay fb", sizeof(fix->id)); 1148c2ecf20Sopenharmony_ci fix->smem_start = dev->video_pbase; 1158c2ecf20Sopenharmony_ci fix->smem_len = dev->video_buffer_size; 1168c2ecf20Sopenharmony_ci fix->type = FB_TYPE_PACKED_PIXELS; 1178c2ecf20Sopenharmony_ci fix->visual = FB_VISUAL_TRUECOLOR; 1188c2ecf20Sopenharmony_ci fix->xpanstep = 1; 1198c2ecf20Sopenharmony_ci fix->ypanstep = 1; 1208c2ecf20Sopenharmony_ci fix->ywrapstep = 0; 1218c2ecf20Sopenharmony_ci fix->line_length = dev->display_byte_stride; 1228c2ecf20Sopenharmony_ci fix->accel = FB_ACCEL_NONE; 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* Check the requested display mode, returning -EINVAL if we can't 1278c2ecf20Sopenharmony_ci handle it. */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *dev) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci dprintk(dev, 1, "vivid_fb_check_var\n"); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 1348c2ecf20Sopenharmony_ci if (var->green.length == 5) { 1358c2ecf20Sopenharmony_ci var->red.offset = 10; 1368c2ecf20Sopenharmony_ci var->red.length = 5; 1378c2ecf20Sopenharmony_ci var->green.offset = 5; 1388c2ecf20Sopenharmony_ci var->green.length = 5; 1398c2ecf20Sopenharmony_ci var->blue.offset = 0; 1408c2ecf20Sopenharmony_ci var->blue.length = 5; 1418c2ecf20Sopenharmony_ci var->transp.offset = 15; 1428c2ecf20Sopenharmony_ci var->transp.length = 1; 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci var->red.offset = 11; 1458c2ecf20Sopenharmony_ci var->red.length = 5; 1468c2ecf20Sopenharmony_ci var->green.offset = 5; 1478c2ecf20Sopenharmony_ci var->green.length = 6; 1488c2ecf20Sopenharmony_ci var->blue.offset = 0; 1498c2ecf20Sopenharmony_ci var->blue.length = 5; 1508c2ecf20Sopenharmony_ci var->transp.offset = 0; 1518c2ecf20Sopenharmony_ci var->transp.length = 0; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci var->xoffset = var->yoffset = 0; 1548c2ecf20Sopenharmony_ci var->left_margin = var->upper_margin = 0; 1558c2ecf20Sopenharmony_ci var->nonstd = 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci var->vmode &= ~FB_VMODE_MASK; 1588c2ecf20Sopenharmony_ci var->vmode |= FB_VMODE_NONINTERLACED; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Dummy values */ 1618c2ecf20Sopenharmony_ci var->hsync_len = 24; 1628c2ecf20Sopenharmony_ci var->vsync_len = 2; 1638c2ecf20Sopenharmony_ci var->pixclock = 84316; 1648c2ecf20Sopenharmony_ci var->right_margin = 776; 1658c2ecf20Sopenharmony_ci var->lower_margin = 591; 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int vivid_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct vivid_dev *dev = (struct vivid_dev *) info->par; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci dprintk(dev, 1, "vivid_fb_check_var\n"); 1748c2ecf20Sopenharmony_ci return _vivid_fb_check_var(var, dev); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int vivid_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int vivid_fb_set_par(struct fb_info *info) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci int rc = 0; 1858c2ecf20Sopenharmony_ci struct vivid_dev *dev = (struct vivid_dev *) info->par; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci dprintk(dev, 1, "vivid_fb_set_par\n"); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci rc = vivid_fb_set_var(dev, &info->var); 1908c2ecf20Sopenharmony_ci vivid_fb_get_fix(dev, &info->fix); 1918c2ecf20Sopenharmony_ci return rc; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int vivid_fb_setcolreg(unsigned regno, unsigned red, unsigned green, 1958c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, 1968c2ecf20Sopenharmony_ci struct fb_info *info) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci u32 color, *palette; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (regno >= info->cmap.len) 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci color = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) | 2048c2ecf20Sopenharmony_ci (green & 0xFF00) | ((blue & 0xFF00) >> 8); 2058c2ecf20Sopenharmony_ci if (regno >= 16) 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci palette = info->pseudo_palette; 2098c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 16) { 2108c2ecf20Sopenharmony_ci switch (info->var.green.length) { 2118c2ecf20Sopenharmony_ci case 6: 2128c2ecf20Sopenharmony_ci color = (red & 0xf800) | 2138c2ecf20Sopenharmony_ci ((green & 0xfc00) >> 5) | 2148c2ecf20Sopenharmony_ci ((blue & 0xf800) >> 11); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case 5: 2178c2ecf20Sopenharmony_ci color = ((red & 0xf800) >> 1) | 2188c2ecf20Sopenharmony_ci ((green & 0xf800) >> 6) | 2198c2ecf20Sopenharmony_ci ((blue & 0xf800) >> 11) | 2208c2ecf20Sopenharmony_ci (transp ? 0x8000 : 0); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci palette[regno] = color; 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* We don't really support blanking. All this does is enable or 2298c2ecf20Sopenharmony_ci disable the OSD. */ 2308c2ecf20Sopenharmony_cistatic int vivid_fb_blank(int blank_mode, struct fb_info *info) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct vivid_dev *dev = (struct vivid_dev *)info->par; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci dprintk(dev, 1, "Set blanking mode : %d\n", blank_mode); 2358c2ecf20Sopenharmony_ci switch (blank_mode) { 2368c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 2398c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 2408c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 2418c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic const struct fb_ops vivid_fb_ops = { 2488c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2498c2ecf20Sopenharmony_ci .fb_check_var = vivid_fb_check_var, 2508c2ecf20Sopenharmony_ci .fb_set_par = vivid_fb_set_par, 2518c2ecf20Sopenharmony_ci .fb_setcolreg = vivid_fb_setcolreg, 2528c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 2538c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 2548c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 2558c2ecf20Sopenharmony_ci .fb_cursor = NULL, 2568c2ecf20Sopenharmony_ci .fb_ioctl = vivid_fb_ioctl, 2578c2ecf20Sopenharmony_ci .fb_pan_display = vivid_fb_pan_display, 2588c2ecf20Sopenharmony_ci .fb_blank = vivid_fb_blank, 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* Initialization */ 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* Setup our initial video mode */ 2658c2ecf20Sopenharmony_cistatic int vivid_fb_init_vidmode(struct vivid_dev *dev) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct v4l2_rect start_window; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* Color mode */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci dev->bits_per_pixel = 16; 2728c2ecf20Sopenharmony_ci dev->bytes_per_pixel = dev->bits_per_pixel / 8; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci start_window.width = MAX_OSD_WIDTH; 2758c2ecf20Sopenharmony_ci start_window.left = 0; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci dev->display_byte_stride = start_window.width * dev->bytes_per_pixel; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Vertical size & position */ 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci start_window.height = MAX_OSD_HEIGHT; 2828c2ecf20Sopenharmony_ci start_window.top = 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci dev->display_width = start_window.width; 2858c2ecf20Sopenharmony_ci dev->display_height = start_window.height; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Generate a valid fb_var_screeninfo */ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci dev->fb_defined.xres = dev->display_width; 2908c2ecf20Sopenharmony_ci dev->fb_defined.yres = dev->display_height; 2918c2ecf20Sopenharmony_ci dev->fb_defined.xres_virtual = dev->display_width; 2928c2ecf20Sopenharmony_ci dev->fb_defined.yres_virtual = dev->display_height; 2938c2ecf20Sopenharmony_ci dev->fb_defined.bits_per_pixel = dev->bits_per_pixel; 2948c2ecf20Sopenharmony_ci dev->fb_defined.vmode = FB_VMODE_NONINTERLACED; 2958c2ecf20Sopenharmony_ci dev->fb_defined.left_margin = start_window.left + 1; 2968c2ecf20Sopenharmony_ci dev->fb_defined.upper_margin = start_window.top + 1; 2978c2ecf20Sopenharmony_ci dev->fb_defined.accel_flags = FB_ACCEL_NONE; 2988c2ecf20Sopenharmony_ci dev->fb_defined.nonstd = 0; 2998c2ecf20Sopenharmony_ci /* set default to 1:5:5:5 */ 3008c2ecf20Sopenharmony_ci dev->fb_defined.green.length = 5; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* We've filled in the most data, let the usual mode check 3038c2ecf20Sopenharmony_ci routine fill in the rest. */ 3048c2ecf20Sopenharmony_ci _vivid_fb_check_var(&dev->fb_defined, dev); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Generate valid fb_fix_screeninfo */ 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci vivid_fb_get_fix(dev, &dev->fb_fix); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Generate valid fb_info */ 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci dev->fb_info.node = -1; 3138c2ecf20Sopenharmony_ci dev->fb_info.flags = FBINFO_FLAG_DEFAULT; 3148c2ecf20Sopenharmony_ci dev->fb_info.par = dev; 3158c2ecf20Sopenharmony_ci dev->fb_info.var = dev->fb_defined; 3168c2ecf20Sopenharmony_ci dev->fb_info.fix = dev->fb_fix; 3178c2ecf20Sopenharmony_ci dev->fb_info.screen_base = (u8 __iomem *)dev->video_vbase; 3188c2ecf20Sopenharmony_ci dev->fb_info.fbops = &vivid_fb_ops; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Supply some monitor specs. Bogus values will do for now */ 3218c2ecf20Sopenharmony_ci dev->fb_info.monspecs.hfmin = 8000; 3228c2ecf20Sopenharmony_ci dev->fb_info.monspecs.hfmax = 70000; 3238c2ecf20Sopenharmony_ci dev->fb_info.monspecs.vfmin = 10; 3248c2ecf20Sopenharmony_ci dev->fb_info.monspecs.vfmax = 100; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Allocate color map */ 3278c2ecf20Sopenharmony_ci if (fb_alloc_cmap(&dev->fb_info.cmap, 256, 1)) { 3288c2ecf20Sopenharmony_ci pr_err("abort, unable to alloc cmap\n"); 3298c2ecf20Sopenharmony_ci return -ENOMEM; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Allocate the pseudo palette */ 3338c2ecf20Sopenharmony_ci dev->fb_info.pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return dev->fb_info.pseudo_palette ? 0 : -ENOMEM; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci/* Release any memory we've grabbed */ 3398c2ecf20Sopenharmony_civoid vivid_fb_release_buffers(struct vivid_dev *dev) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci if (dev->video_vbase == NULL) 3428c2ecf20Sopenharmony_ci return; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Release cmap */ 3458c2ecf20Sopenharmony_ci if (dev->fb_info.cmap.len) 3468c2ecf20Sopenharmony_ci fb_dealloc_cmap(&dev->fb_info.cmap); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Release pseudo palette */ 3498c2ecf20Sopenharmony_ci kfree(dev->fb_info.pseudo_palette); 3508c2ecf20Sopenharmony_ci kfree(dev->video_vbase); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* Initialize the specified card */ 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciint vivid_fb_init(struct vivid_dev *dev) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int ret; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2; 3608c2ecf20Sopenharmony_ci dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32); 3618c2ecf20Sopenharmony_ci if (dev->video_vbase == NULL) 3628c2ecf20Sopenharmony_ci return -ENOMEM; 3638c2ecf20Sopenharmony_ci dev->video_pbase = virt_to_phys(dev->video_vbase); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", 3668c2ecf20Sopenharmony_ci dev->video_pbase, dev->video_vbase, 3678c2ecf20Sopenharmony_ci dev->video_buffer_size / 1024); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* Set the startup video mode information */ 3708c2ecf20Sopenharmony_ci ret = vivid_fb_init_vidmode(dev); 3718c2ecf20Sopenharmony_ci if (ret) { 3728c2ecf20Sopenharmony_ci vivid_fb_release_buffers(dev); 3738c2ecf20Sopenharmony_ci return ret; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci vivid_clear_fb(dev); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Register the framebuffer */ 3798c2ecf20Sopenharmony_ci if (register_framebuffer(&dev->fb_info) < 0) { 3808c2ecf20Sopenharmony_ci vivid_fb_release_buffers(dev); 3818c2ecf20Sopenharmony_ci return -EINVAL; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Set the card to the requested mode */ 3858c2ecf20Sopenharmony_ci vivid_fb_set_par(&dev->fb_info); 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci} 389