root/samples/vfio-mdev/mdpy-fb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mdpy_fb_setcolreg
  2. mdpy_fb_destroy
  3. mdpy_fb_probe
  4. mdpy_fb_remove
  5. mdpy_fb_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Framebuffer driver for mdpy (mediated virtual pci display device).
   4  *
   5  * See mdpy-defs.h for device specs
   6  *
   7  *   (c) Gerd Hoffmann <kraxel@redhat.com>
   8  *
   9  * Using some code snippets from simplefb and cirrusfb.
  10  *
  11  * This program is free software; you can redistribute it and/or modify it
  12  * under the terms and conditions of the GNU General Public License,
  13  * version 2, as published by the Free Software Foundation.
  14  *
  15  * This program is distributed in the hope it will be useful, but WITHOUT
  16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  18  * more details.
  19  */
  20 #include <linux/errno.h>
  21 #include <linux/fb.h>
  22 #include <linux/io.h>
  23 #include <linux/pci.h>
  24 #include <linux/module.h>
  25 #include <drm/drm_fourcc.h>
  26 #include "mdpy-defs.h"
  27 
  28 static const struct fb_fix_screeninfo mdpy_fb_fix = {
  29         .id             = "mdpy-fb",
  30         .type           = FB_TYPE_PACKED_PIXELS,
  31         .visual         = FB_VISUAL_TRUECOLOR,
  32         .accel          = FB_ACCEL_NONE,
  33 };
  34 
  35 static const struct fb_var_screeninfo mdpy_fb_var = {
  36         .height         = -1,
  37         .width          = -1,
  38         .activate       = FB_ACTIVATE_NOW,
  39         .vmode          = FB_VMODE_NONINTERLACED,
  40 
  41         .bits_per_pixel = 32,
  42         .transp.offset  = 24,
  43         .red.offset     = 16,
  44         .green.offset   = 8,
  45         .blue.offset    = 0,
  46         .transp.length  = 8,
  47         .red.length     = 8,
  48         .green.length   = 8,
  49         .blue.length    = 8,
  50 };
  51 
  52 #define PSEUDO_PALETTE_SIZE 16
  53 
  54 struct mdpy_fb_par {
  55         u32 palette[PSEUDO_PALETTE_SIZE];
  56 };
  57 
  58 static int mdpy_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  59                               u_int transp, struct fb_info *info)
  60 {
  61         u32 *pal = info->pseudo_palette;
  62         u32 cr = red >> (16 - info->var.red.length);
  63         u32 cg = green >> (16 - info->var.green.length);
  64         u32 cb = blue >> (16 - info->var.blue.length);
  65         u32 value, mask;
  66 
  67         if (regno >= PSEUDO_PALETTE_SIZE)
  68                 return -EINVAL;
  69 
  70         value = (cr << info->var.red.offset) |
  71                 (cg << info->var.green.offset) |
  72                 (cb << info->var.blue.offset);
  73         if (info->var.transp.length > 0) {
  74                 mask = (1 << info->var.transp.length) - 1;
  75                 mask <<= info->var.transp.offset;
  76                 value |= mask;
  77         }
  78         pal[regno] = value;
  79 
  80         return 0;
  81 }
  82 
  83 static void mdpy_fb_destroy(struct fb_info *info)
  84 {
  85         if (info->screen_base)
  86                 iounmap(info->screen_base);
  87 }
  88 
  89 static struct fb_ops mdpy_fb_ops = {
  90         .owner          = THIS_MODULE,
  91         .fb_destroy     = mdpy_fb_destroy,
  92         .fb_setcolreg   = mdpy_fb_setcolreg,
  93         .fb_fillrect    = cfb_fillrect,
  94         .fb_copyarea    = cfb_copyarea,
  95         .fb_imageblit   = cfb_imageblit,
  96 };
  97 
  98 static int mdpy_fb_probe(struct pci_dev *pdev,
  99                          const struct pci_device_id *ent)
 100 {
 101         struct fb_info *info;
 102         struct mdpy_fb_par *par;
 103         u32 format, width, height;
 104         int ret;
 105 
 106         ret = pci_enable_device(pdev);
 107         if (ret < 0)
 108                 return ret;
 109 
 110         ret = pci_request_regions(pdev, "mdpy-fb");
 111         if (ret < 0)
 112                 return ret;
 113 
 114         pci_read_config_dword(pdev, MDPY_FORMAT_OFFSET, &format);
 115         pci_read_config_dword(pdev, MDPY_WIDTH_OFFSET,  &width);
 116         pci_read_config_dword(pdev, MDPY_HEIGHT_OFFSET, &height);
 117         if (format != DRM_FORMAT_XRGB8888) {
 118                 pci_err(pdev, "format mismatch (0x%x != 0x%x)\n",
 119                         format, DRM_FORMAT_XRGB8888);
 120                 return -EINVAL;
 121         }
 122         if (width < 100  || width > 10000) {
 123                 pci_err(pdev, "width (%d) out of range\n", width);
 124                 return -EINVAL;
 125         }
 126         if (height < 100 || height > 10000) {
 127                 pci_err(pdev, "height (%d) out of range\n", height);
 128                 return -EINVAL;
 129         }
 130         pci_info(pdev, "mdpy found: %dx%d framebuffer\n",
 131                  width, height);
 132 
 133         info = framebuffer_alloc(sizeof(struct mdpy_fb_par), &pdev->dev);
 134         if (!info)
 135                 goto err_release_regions;
 136         pci_set_drvdata(pdev, info);
 137         par = info->par;
 138 
 139         info->fix = mdpy_fb_fix;
 140         info->fix.smem_start = pci_resource_start(pdev, 0);
 141         info->fix.smem_len = pci_resource_len(pdev, 0);
 142         info->fix.line_length = width * 4;
 143 
 144         info->var = mdpy_fb_var;
 145         info->var.xres = width;
 146         info->var.yres = height;
 147         info->var.xres_virtual = width;
 148         info->var.yres_virtual = height;
 149 
 150         info->screen_size = info->fix.smem_len;
 151         info->screen_base = ioremap(info->fix.smem_start,
 152                                     info->screen_size);
 153         if (!info->screen_base) {
 154                 pci_err(pdev, "ioremap(pcibar) failed\n");
 155                 ret = -EIO;
 156                 goto err_release_fb;
 157         }
 158 
 159         info->apertures = alloc_apertures(1);
 160         if (!info->apertures) {
 161                 ret = -ENOMEM;
 162                 goto err_unmap;
 163         }
 164         info->apertures->ranges[0].base = info->fix.smem_start;
 165         info->apertures->ranges[0].size = info->fix.smem_len;
 166 
 167         info->fbops = &mdpy_fb_ops;
 168         info->flags = FBINFO_DEFAULT;
 169         info->pseudo_palette = par->palette;
 170 
 171         ret = register_framebuffer(info);
 172         if (ret < 0) {
 173                 pci_err(pdev, "mdpy-fb device register failed: %d\n", ret);
 174                 goto err_unmap;
 175         }
 176 
 177         pci_info(pdev, "fb%d registered\n", info->node);
 178         return 0;
 179 
 180 err_unmap:
 181         iounmap(info->screen_base);
 182 
 183 err_release_fb:
 184         framebuffer_release(info);
 185 
 186 err_release_regions:
 187         pci_release_regions(pdev);
 188 
 189         return ret;
 190 }
 191 
 192 static void mdpy_fb_remove(struct pci_dev *pdev)
 193 {
 194         struct fb_info *info = pci_get_drvdata(pdev);
 195 
 196         unregister_framebuffer(info);
 197         framebuffer_release(info);
 198 }
 199 
 200 static struct pci_device_id mdpy_fb_pci_table[] = {
 201         {
 202                 .vendor    = MDPY_PCI_VENDOR_ID,
 203                 .device    = MDPY_PCI_DEVICE_ID,
 204                 .subvendor = MDPY_PCI_SUBVENDOR_ID,
 205                 .subdevice = MDPY_PCI_SUBDEVICE_ID,
 206         }, {
 207                 /* end of list */
 208         }
 209 };
 210 
 211 static struct pci_driver mdpy_fb_pci_driver = {
 212         .name           = "mdpy-fb",
 213         .id_table       = mdpy_fb_pci_table,
 214         .probe          = mdpy_fb_probe,
 215         .remove         = mdpy_fb_remove,
 216 };
 217 
 218 static int __init mdpy_fb_init(void)
 219 {
 220         int ret;
 221 
 222         ret = pci_register_driver(&mdpy_fb_pci_driver);
 223         if (ret)
 224                 return ret;
 225 
 226         return 0;
 227 }
 228 
 229 module_init(mdpy_fb_init);
 230 
 231 MODULE_DEVICE_TABLE(pci, mdpy_fb_pci_table);
 232 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */