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