^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * udlfb.c -- Framebuffer driver for DisplayLink USB controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * usb-skeleton by GregKH.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Device-specific portions based on information from Displaylink, with work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * from Florian Echtler, Henrik Bjerregaard Pedersen, and others.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/usb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <video/udlfb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "edid.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static const struct fb_fix_screeninfo dlfb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) .id = "udlfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .visual = FB_VISUAL_TRUECOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .xpanstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .ypanstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .ywrapstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .accel = FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) FBINFO_VIRTFB |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * There are many DisplayLink-based graphics products, all with unique PIDs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * We also require a match on SubClass (0x00) and Protocol (0x00),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * which is compatible with all known USB 2.0 era graphics chips and firmware,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * but allows DisplayLink to increment those for any future incompatible chips
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static const struct usb_device_id id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {.idVendor = 0x17e9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .bInterfaceClass = 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .bInterfaceSubClass = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .bInterfaceProtocol = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) USB_DEVICE_ID_MATCH_INT_CLASS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) USB_DEVICE_ID_MATCH_INT_SUBCLASS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) USB_DEVICE_ID_MATCH_INT_PROTOCOL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) MODULE_DEVICE_TABLE(usb, id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* module options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static bool console = true; /* Allow fbcon to open framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static bool fb_defio = true; /* Detect mmap writes using page faults */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static bool shadow = true; /* Optionally disable shadow framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int pixel_limit; /* Optionally force a pixel resolution limit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct dlfb_deferred_free {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) void *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* dlfb keeps a list of urbs for efficient bulk transfers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static void dlfb_urb_completion(struct urb *urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static struct urb *dlfb_get_urb(struct dlfb_data *dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int dlfb_submit_urb(struct dlfb_data *dlfb, struct urb * urb, size_t len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static void dlfb_free_urb_list(struct dlfb_data *dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * All DisplayLink bulk operations start with 0xAF, followed by specific code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * All operations are written to buffers which then later get sent to device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static char *dlfb_set_register(char *buf, u8 reg, u8 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) *buf++ = 0xAF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *buf++ = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) *buf++ = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) *buf++ = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static char *dlfb_vidreg_lock(char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return dlfb_set_register(buf, 0xFF, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static char *dlfb_vidreg_unlock(char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return dlfb_set_register(buf, 0xFF, 0xFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * Map FB_BLANK_* to DisplayLink register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * DLReg FB_BLANK_*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * ----- -----------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * 0x00 FB_BLANK_UNBLANK (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * 0x01 FB_BLANK (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * 0x03 FB_BLANK_VSYNC_SUSPEND (2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * 0x05 FB_BLANK_HSYNC_SUSPEND (3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * 0x07 FB_BLANK_POWERDOWN (4) Note: requires modeset to come back
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static char *dlfb_blanking(char *buf, int fb_blank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) switch (fb_blank) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) reg = 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) reg = 0x05;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) reg = 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) reg = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) reg = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) buf = dlfb_set_register(buf, 0x1F, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static char *dlfb_set_color_depth(char *buf, u8 selection)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return dlfb_set_register(buf, 0x00, selection);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static char *dlfb_set_base16bpp(char *wrptr, u32 base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* the base pointer is 16 bits wide, 0x20 is hi byte. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) wrptr = dlfb_set_register(wrptr, 0x20, base >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) wrptr = dlfb_set_register(wrptr, 0x21, base >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return dlfb_set_register(wrptr, 0x22, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * DisplayLink HW has separate 16bpp and 8bpp framebuffers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static char *dlfb_set_base8bpp(char *wrptr, u32 base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) wrptr = dlfb_set_register(wrptr, 0x27, base >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return dlfb_set_register(wrptr, 0x28, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) wrptr = dlfb_set_register(wrptr, reg, value >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return dlfb_set_register(wrptr, reg+1, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * This is kind of weird because the controller takes some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * register values in a different byte order than other registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) wrptr = dlfb_set_register(wrptr, reg, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return dlfb_set_register(wrptr, reg+1, value >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * LFSR is linear feedback shift register. The reason we have this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * because the display controller needs to minimize the clock depth of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * various counters used in the display path. So this code reverses the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * provided value into the lfsr16 value by counting backwards to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * the value that needs to be set in the hardware comparator to get the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * same actual count. This makes sense once you read above a couple of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * times and think about it from a hardware perspective.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) static u16 dlfb_lfsr16(u16 actual_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) while (actual_count--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) lv = ((lv << 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) & 0xFFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return (u16) lv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * This does LFSR conversion on the value that is to be written.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * See LFSR explanation above for more detail.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return dlfb_set_register_16(wrptr, reg, dlfb_lfsr16(value));
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * This takes a standard fbdev screeninfo struct and all of its monitor mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * details and converts them into the DisplayLink equivalent register commands.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) u16 xds, yds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) u16 xde, yde;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) u16 yec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* x display start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) xds = var->left_margin + var->hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) /* x display end */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) xde = xds + var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /* y display start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) yds = var->upper_margin + var->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /* y display end */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) yde = yds + var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) /* x end count is active + blanking - 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) wrptr = dlfb_set_register_lfsr16(wrptr, 0x09,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) xde + var->right_margin - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /* libdlo hardcodes hsync start to 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* hsync end is width of sync pulse + 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /* hpixels is active pixels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* yendcount is vertical active + vertical blanking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) yec = var->yres + var->upper_margin + var->lower_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) var->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* libdlo hardcodes vsync start to 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* vsync end is width of vsync pulse */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /* vpixels is active pixels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) wrptr = dlfb_set_register_16be(wrptr, 0x1B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 200*1000*1000/var->pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return wrptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * This takes a standard fbdev screeninfo struct that was fetched or prepared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * and then generates the appropriate command sequence that then drives the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * display controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static int dlfb_set_video_mode(struct dlfb_data *dlfb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) char *wrptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) int writesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct urb *urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (!atomic_read(&dlfb->usb_active))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) urb = dlfb_get_urb(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) buf = (char *) urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * This first section has to do with setting the base address on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * controller * associated with the display. There are 2 base
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * pointers, currently, we only * use the 16 bpp segment.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) wrptr = dlfb_vidreg_lock(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) wrptr = dlfb_set_color_depth(wrptr, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) /* set base for 16bpp segment to 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) wrptr = dlfb_set_base16bpp(wrptr, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* set base for 8bpp segment to end of fb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) wrptr = dlfb_set_base8bpp(wrptr, dlfb->info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) wrptr = dlfb_set_vid_cmds(wrptr, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) wrptr = dlfb_blanking(wrptr, FB_BLANK_UNBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) wrptr = dlfb_vidreg_unlock(wrptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) writesize = wrptr - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) retval = dlfb_submit_urb(dlfb, urb, writesize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) dlfb->blank_mode = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) unsigned long start = vma->vm_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) unsigned long size = vma->vm_end - vma->vm_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) unsigned long page, pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (size > info->fix.smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (offset > info->fix.smem_len - size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) pos = (unsigned long)info->fix.smem_start + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) dev_dbg(info->dev, "mmap() framebuffer addr:%lu size:%lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) pos, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) while (size > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) page = vmalloc_to_pfn((void *)pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) start += PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) pos += PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (size > PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) size -= PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) * Trims identical data from front and back of line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * Sets new front buffer address and width
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * And returns byte count of identical pixels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * Assumes CPU natural alignment (unsigned long)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * for back and front buffer ptrs and width
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) int j, k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) const unsigned long *back = (const unsigned long *) bback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) const unsigned long *front = (const unsigned long *) *bfront;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) const int width = *width_bytes / sizeof(unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) int identical = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) int start = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) int end = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) for (j = 0; j < width; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (back[j] != front[j]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) start = j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) for (k = width - 1; k > j; k--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (back[k] != front[k]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) end = k+1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) identical = start + (width - end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) *bfront = (u8 *) &front[start];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) *width_bytes = (end - start) * sizeof(unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return identical * sizeof(unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * Render a command stream for an encoded horizontal line segment of pixels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * A command buffer holds several commands.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * It always begins with a fresh command header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * (the protocol doesn't require this, but we enforce it to allow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * multiple buffers to be potentially encoded and sent in parallel).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) * A single command encodes one contiguous horizontal line of pixels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * The function relies on the client to do all allocation, so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) * rendering can be done directly to output buffers (e.g. USB URBs).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * The function fills the supplied command buffer, providing information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * on where it left off, so the client may call in again with additional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * buffers if the line will take several buffers to complete.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * A single command can transmit a maximum of 256 pixels,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) * regardless of the compression ratio (protocol design limit).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) * To the hardware, 0 for a size byte means 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) * Rather than 256 pixel commands which are either rl or raw encoded,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * the rlx command simply assumes alternating raw and rl spans within one cmd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * This has a slightly larger header overhead, but produces more even results.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * It also processes all data (read and write) in a single pass.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * Performance benchmarks of common cases show it having just slightly better
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * compression than 256 pixel raw or rle commands, with similar CPU consumpion.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) * But for very rl friendly data, will compress not quite as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static void dlfb_compress_hline(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) const uint16_t **pixel_start_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) const uint16_t *const pixel_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) uint32_t *device_address_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) uint8_t **command_buffer_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) const uint8_t *const cmd_buffer_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) unsigned long back_buffer_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) int *ident_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) const uint16_t *pixel = *pixel_start_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) uint32_t dev_addr = *device_address_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) uint8_t *cmd = *command_buffer_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) while ((pixel_end > pixel) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) uint8_t *raw_pixels_count_byte = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) uint8_t *cmd_pixels_count_byte = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) const uint16_t *raw_pixel_start = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) const uint16_t *cmd_pixel_start, *cmd_pixel_end = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (back_buffer_offset &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) *pixel == *(u16 *)((u8 *)pixel + back_buffer_offset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) pixel++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) dev_addr += BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) (*ident_ptr)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) *cmd++ = 0xAF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) *cmd++ = 0x6B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) *cmd++ = dev_addr >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) *cmd++ = dev_addr >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) *cmd++ = dev_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) cmd_pixels_count_byte = cmd++; /* we'll know this later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) cmd_pixel_start = pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) raw_pixels_count_byte = cmd++; /* we'll know this later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) raw_pixel_start = pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) (unsigned long)(pixel_end - pixel),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) (unsigned long)(cmd_buffer_end - 1 - cmd) / BPP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (back_buffer_offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) /* note: the framebuffer may change under us, so we must test for underflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) while (cmd_pixel_end - 1 > pixel &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) *(cmd_pixel_end - 1) == *(u16 *)((u8 *)(cmd_pixel_end - 1) + back_buffer_offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) cmd_pixel_end--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) while (pixel < cmd_pixel_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) const uint16_t * const repeating_pixel = pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) u16 pixel_value = *pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) put_unaligned_be16(pixel_value, cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (back_buffer_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) cmd += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) pixel++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (unlikely((pixel < cmd_pixel_end) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) (*pixel == pixel_value))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) /* go back and fill in raw pixel count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) *raw_pixels_count_byte = ((repeating_pixel -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) raw_pixel_start) + 1) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (back_buffer_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) pixel++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) } while ((pixel < cmd_pixel_end) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) (*pixel == pixel_value));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /* immediately after raw data is repeat byte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) /* Then start another raw pixel span */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) raw_pixel_start = pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) raw_pixels_count_byte = cmd++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (pixel > raw_pixel_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /* finalize last RAW span */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) /* undo unused byte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) cmd--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) dev_addr += (u8 *)pixel - (u8 *)cmd_pixel_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (cmd_buffer_end - MIN_RLX_CMD_BYTES <= cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* Fill leftover bytes with no-ops */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (cmd_buffer_end > cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) memset(cmd, 0xAF, cmd_buffer_end - cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) cmd = (uint8_t *) cmd_buffer_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) *command_buffer_ptr = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) *pixel_start_ptr = pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) *device_address_ptr = dev_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * There are 3 copies of every pixel: The front buffer that the fbdev
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * client renders to, the actual framebuffer across the USB bus in hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) * (that we can only write to, slowly, and can never read), and (optionally)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * our shadow copy that tracks what's been sent to that hardware buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) const char *front, char **urb_buf_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) u32 byte_offset, u32 byte_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) int *ident_ptr, int *sent_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) const u8 *line_start, *line_end, *next_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) u32 dev_addr = dlfb->base16 + byte_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) struct urb *urb = *urb_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) u8 *cmd = *urb_buf_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) unsigned long back_buffer_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) line_start = (u8 *) (front + byte_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) next_pixel = line_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) line_end = next_pixel + byte_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if (dlfb->backing_buffer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) const u8 *back_start = (u8 *) (dlfb->backing_buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) + byte_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) back_buffer_offset = (unsigned long)back_start - (unsigned long)line_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) *ident_ptr += dlfb_trim_hline(back_start, &next_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) &byte_width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) offset = next_pixel - line_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) line_end = next_pixel + byte_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) dev_addr += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) back_start += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) line_start += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) while (next_pixel < line_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) dlfb_compress_hline((const uint16_t **) &next_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) (const uint16_t *) line_end, &dev_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) (u8 **) &cmd, (u8 *) cmd_end, back_buffer_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) ident_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (cmd >= cmd_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) int len = cmd - (u8 *) urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (dlfb_submit_urb(dlfb, urb, len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) return 1; /* lost pixels is set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) *sent_ptr += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) urb = dlfb_get_urb(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return 1; /* lost_pixels is set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) *urb_ptr = urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) cmd = urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) cmd_end = &cmd[urb->transfer_buffer_length];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) *urb_buf_ptr = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, int height)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) char *cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) cycles_t start_cycles, end_cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) int bytes_sent = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) int bytes_identical = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) struct urb *urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) int aligned_x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) start_cycles = get_cycles();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) mutex_lock(&dlfb->render_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) x = aligned_x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if ((width <= 0) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) (x + width > dlfb->info->var.xres) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) (y + height > dlfb->info->var.yres)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) goto unlock_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) if (!atomic_read(&dlfb->usb_active)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) goto unlock_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) urb = dlfb_get_urb(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) if (!urb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) goto unlock_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) cmd = urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) for (i = y; i < y + height ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) const int line_offset = dlfb->info->fix.line_length * i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) const int byte_offset = line_offset + (x * BPP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (dlfb_render_hline(dlfb, &urb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) (char *) dlfb->info->fix.smem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) &cmd, byte_offset, width * BPP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) &bytes_identical, &bytes_sent))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if (cmd > (char *) urb->transfer_buffer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) *cmd++ = 0xAF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) /* Send partial buffer remaining before exiting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) len = cmd - (char *) urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) dlfb_submit_urb(dlfb, urb, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) bytes_sent += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) dlfb_urb_completion(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) atomic_add(bytes_sent, &dlfb->bytes_sent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) atomic_add(bytes_identical, &dlfb->bytes_identical);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) atomic_add(width*height*2, &dlfb->bytes_rendered);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) end_cycles = get_cycles();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) atomic_add(((unsigned int) ((end_cycles - start_cycles)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) >> 10)), /* Kcycles */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) &dlfb->cpu_kcycles_used);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) unlock_ret:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) mutex_unlock(&dlfb->render_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) static void dlfb_init_damage(struct dlfb_data *dlfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) dlfb->damage_x = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) dlfb->damage_x2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) dlfb->damage_y = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) dlfb->damage_y2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) static void dlfb_damage_work(struct work_struct *w)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) struct dlfb_data *dlfb = container_of(w, struct dlfb_data, damage_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) int x, x2, y, y2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) spin_lock_irq(&dlfb->damage_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) x = dlfb->damage_x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) x2 = dlfb->damage_x2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) y = dlfb->damage_y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) y2 = dlfb->damage_y2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) dlfb_init_damage(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) spin_unlock_irq(&dlfb->damage_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) if (x < x2 && y < y2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) dlfb_handle_damage(dlfb, x, y, x2 - x, y2 - y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) static void dlfb_offload_damage(struct dlfb_data *dlfb, int x, int y, int width, int height)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) int x2 = x + width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) int y2 = y + height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (x >= x2 || y >= y2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) spin_lock_irqsave(&dlfb->damage_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) dlfb->damage_x = min(x, dlfb->damage_x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) dlfb->damage_x2 = max(x2, dlfb->damage_x2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) dlfb->damage_y = min(y, dlfb->damage_y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) dlfb->damage_y2 = max(y2, dlfb->damage_y2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) spin_unlock_irqrestore(&dlfb->damage_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) schedule_work(&dlfb->damage_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) * Path triggered by usermode clients who write to filesystem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) * e.g. cat filename > /dev/fb1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) * Not used by X Windows or text-mode console. But useful for testing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) * Slow because of extra copy and we must assume all pixels dirty.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) ssize_t result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) u32 offset = (u32) *ppos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) result = fb_sys_write(info, buf, count, ppos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) if (result > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) int start = max((int)(offset / info->fix.line_length), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) int lines = min((u32)((result / info->fix.line_length) + 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) (u32)info->var.yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) dlfb_handle_damage(dlfb, 0, start, info->var.xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) lines);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) /* hardware has native COPY command (see libdlo), but not worth it for fbcon */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) static void dlfb_ops_copyarea(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) const struct fb_copyarea *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) sys_copyarea(info, area);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) dlfb_offload_damage(dlfb, area->dx, area->dy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) area->width, area->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) static void dlfb_ops_imageblit(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) const struct fb_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) sys_imageblit(info, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) dlfb_offload_damage(dlfb, image->dx, image->dy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) image->width, image->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) static void dlfb_ops_fillrect(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) const struct fb_fillrect *rect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) sys_fillrect(info, rect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) dlfb_offload_damage(dlfb, rect->dx, rect->dy, rect->width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) rect->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) * NOTE: fb_defio.c is holding info->fbdefio.mutex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) * Touching ANY framebuffer memory that triggers a page fault
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) * in fb_defio will cause a deadlock, when it also tries to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) * grab the same mutex.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) static void dlfb_dpy_deferred_io(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) struct list_head *pagelist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) struct page *cur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) struct fb_deferred_io *fbdefio = info->fbdefio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) struct urb *urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) char *cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) cycles_t start_cycles, end_cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) int bytes_sent = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) int bytes_identical = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) int bytes_rendered = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) mutex_lock(&dlfb->render_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) if (!fb_defio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) goto unlock_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (!atomic_read(&dlfb->usb_active))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) goto unlock_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) start_cycles = get_cycles();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) urb = dlfb_get_urb(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) goto unlock_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) cmd = urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) /* walk the written page list and render each to device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) list_for_each_entry(cur, &fbdefio->pagelist, lru) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (dlfb_render_hline(dlfb, &urb, (char *) info->fix.smem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) &cmd, cur->index << PAGE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) PAGE_SIZE, &bytes_identical, &bytes_sent))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) bytes_rendered += PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) if (cmd > (char *) urb->transfer_buffer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) *cmd++ = 0xAF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) /* Send partial buffer remaining before exiting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) len = cmd - (char *) urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) dlfb_submit_urb(dlfb, urb, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) bytes_sent += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) dlfb_urb_completion(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) atomic_add(bytes_sent, &dlfb->bytes_sent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) atomic_add(bytes_identical, &dlfb->bytes_identical);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) atomic_add(bytes_rendered, &dlfb->bytes_rendered);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) end_cycles = get_cycles();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) atomic_add(((unsigned int) ((end_cycles - start_cycles)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) >> 10)), /* Kcycles */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) &dlfb->cpu_kcycles_used);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) unlock_ret:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) mutex_unlock(&dlfb->render_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) static int dlfb_get_edid(struct dlfb_data *dlfb, char *edid, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) char *rbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) rbuf = kmalloc(2, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) if (!rbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) for (i = 0; i < len; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) ret = usb_control_msg(dlfb->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) usb_rcvctrlpipe(dlfb->udev, 0), 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) (0x80 | (0x02 << 5)), i << 8, 0xA1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) rbuf, 2, USB_CTRL_GET_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) if (ret < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) dev_err(&dlfb->udev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) "Read EDID byte %d failed: %d\n", i, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) i--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) edid[i] = rbuf[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) kfree(rbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (!atomic_read(&dlfb->usb_active))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) /* TODO: Update X server to get this from sysfs instead */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (cmd == DLFB_IOCTL_RETURN_EDID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) void __user *edid = (void __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) if (copy_to_user(edid, dlfb->edid, dlfb->edid_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) struct dloarea area;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) if (copy_from_user(&area, (void __user *)arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) sizeof(struct dloarea)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) * If we have a damage-aware client, turn fb_defio "off"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) * To avoid perf imact of unnecessary page fault handling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) * Done by resetting the delay for this fb_info to a very
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) * long period. Pages will become writable and stay that way.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) * Reset to normal value when all clients have closed this fb.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) if (info->fbdefio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) info->fbdefio->delay = DL_DEFIO_WRITE_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) if (area.x < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) area.x = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) if (area.x > info->var.xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) area.x = info->var.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) if (area.y < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) area.y = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) if (area.y > info->var.yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) area.y = info->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) dlfb_handle_damage(dlfb, area.x, area.y, area.w, area.h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) /* taken from vesafb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) unsigned blue, unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) if (regno >= info->cmap.len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) if (info->var.red.offset == 10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) /* 1:5:5:5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) ((u32 *) (info->pseudo_palette))[regno] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) ((red & 0xf800) >> 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) /* 0:5:6:5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) ((u32 *) (info->pseudo_palette))[regno] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) ((red & 0xf800)) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) * It's common for several clients to have framebuffer open simultaneously.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) * e.g. both fbcon and X. Makes things interesting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) * Assumes caller is holding info->lock (for open and release at least)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) static int dlfb_ops_open(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) * fbcon aggressively connects to first framebuffer it finds,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) * preventing other clients (X) from working properly. Usually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) * not what the user wants. Fail by default with option to enable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) if ((user == 0) && (!console))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) /* If the USB device is gone, we don't accept new opens */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (dlfb->virtualized)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) dlfb->fb_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) if (fb_defio && (info->fbdefio == NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) /* enable defio at last moment if not disabled by client */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) struct fb_deferred_io *fbdefio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) if (fbdefio) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) fbdefio->delay = DL_DEFIO_WRITE_DELAY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) fbdefio->deferred_io = dlfb_dpy_deferred_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) info->fbdefio = fbdefio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) fb_deferred_io_init(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) dev_dbg(info->dev, "open, user=%d fb_info=%p count=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) user, info, dlfb->fb_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) static void dlfb_ops_destroy(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) cancel_work_sync(&dlfb->damage_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) mutex_destroy(&dlfb->render_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) if (info->cmap.len != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) if (info->monspecs.modedb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) fb_destroy_modedb(info->monspecs.modedb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) vfree(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) fb_destroy_modelist(&info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) while (!list_empty(&dlfb->deferred_free)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) struct dlfb_deferred_free *d = list_entry(dlfb->deferred_free.next, struct dlfb_deferred_free, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) list_del(&d->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) vfree(d->mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) kfree(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) vfree(dlfb->backing_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) kfree(dlfb->edid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) dlfb_free_urb_list(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) usb_put_dev(dlfb->udev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) kfree(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) /* Assume info structure is freed after this point */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) * Assumes caller is holding info->lock mutex (for open and release at least)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) static int dlfb_ops_release(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) dlfb->fb_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) if ((dlfb->fb_count == 0) && (info->fbdefio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) fb_deferred_io_cleanup(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) kfree(info->fbdefio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) info->fbdefio = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) dev_dbg(info->dev, "release, user=%d count=%d\n", user, dlfb->fb_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) * Check whether a video mode is supported by the DisplayLink chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) * We start from monitor's modes, so don't need to filter that here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) static int dlfb_is_valid_mode(struct fb_videomode *mode, struct dlfb_data *dlfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) if (mode->xres * mode->yres > dlfb->sku_pixel_limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) static void dlfb_var_color_format(struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) const struct fb_bitfield red = { 11, 5, 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) const struct fb_bitfield green = { 5, 6, 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) const struct fb_bitfield blue = { 0, 5, 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) var->red = red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) var->green = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) var->blue = blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) struct fb_videomode mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) /* set device-specific elements of var unrelated to mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) dlfb_var_color_format(var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) fb_var_to_videomode(&mode, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (!dlfb_is_valid_mode(&mode, dlfb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) static int dlfb_ops_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) u16 *pix_framebuffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) struct fb_var_screeninfo fvs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) u32 line_length = info->var.xres * (info->var.bits_per_pixel / 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) /* clear the activate field because it causes spurious miscompares */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) fvs = info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) fvs.activate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) fvs.vmode &= ~FB_VMODE_SMOOTH_XPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) if (!memcmp(&dlfb->current_mode, &fvs, sizeof(struct fb_var_screeninfo)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) result = dlfb_realloc_framebuffer(dlfb, info, info->var.yres * line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) result = dlfb_set_video_mode(dlfb, &info->var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) dlfb->current_mode = fvs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) info->fix.line_length = line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) if (dlfb->fb_count == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) /* paint greenscreen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) pix_framebuffer = (u16 *) info->screen_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) for (i = 0; i < info->fix.smem_len / 2; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) pix_framebuffer[i] = 0x37e6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) /* To fonzi the jukebox (e.g. make blanking changes take effect) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) static char *dlfb_dummy_render(char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) *buf++ = 0xAF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) *buf++ = 0x6A; /* copy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) *buf++ = 0x00; /* from address*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) *buf++ = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) *buf++ = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) *buf++ = 0x01; /* one pixel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) *buf++ = 0x00; /* to address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) *buf++ = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) *buf++ = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) * In order to come back from full DPMS off, we need to set the mode again
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) struct dlfb_data *dlfb = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) char *bufptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) struct urb *urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) dev_dbg(info->dev, "blank, mode %d --> %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) dlfb->blank_mode, blank_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) if ((dlfb->blank_mode == FB_BLANK_POWERDOWN) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) (blank_mode != FB_BLANK_POWERDOWN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) /* returning from powerdown requires a fresh modeset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) dlfb_set_video_mode(dlfb, &info->var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) urb = dlfb_get_urb(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) bufptr = (char *) urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) bufptr = dlfb_vidreg_lock(bufptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) bufptr = dlfb_blanking(bufptr, blank_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) bufptr = dlfb_vidreg_unlock(bufptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) /* seems like a render op is needed to have blank change take effect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) bufptr = dlfb_dummy_render(bufptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) dlfb_submit_urb(dlfb, urb, bufptr -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) (char *) urb->transfer_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) dlfb->blank_mode = blank_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) static const struct fb_ops dlfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) .fb_read = fb_sys_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) .fb_write = dlfb_ops_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) .fb_setcolreg = dlfb_ops_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) .fb_fillrect = dlfb_ops_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) .fb_copyarea = dlfb_ops_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) .fb_imageblit = dlfb_ops_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) .fb_mmap = dlfb_ops_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) .fb_ioctl = dlfb_ops_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) .fb_open = dlfb_ops_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) .fb_release = dlfb_ops_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) .fb_blank = dlfb_ops_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) .fb_check_var = dlfb_ops_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) .fb_set_par = dlfb_ops_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) .fb_destroy = dlfb_ops_destroy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) static void dlfb_deferred_vfree(struct dlfb_data *dlfb, void *mem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) struct dlfb_deferred_free *d = kmalloc(sizeof(struct dlfb_deferred_free), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) if (!d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) d->mem = mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) list_add(&d->list, &dlfb->deferred_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) * Assumes &info->lock held by caller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) * Assumes no active clients have framebuffer open
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) u32 old_len = info->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) const void *old_fb = (const void __force *)info->screen_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) unsigned char *new_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) unsigned char *new_back = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) new_len = PAGE_ALIGN(new_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) if (new_len > old_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) * Alloc system memory for virtual framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) new_fb = vmalloc(new_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) if (!new_fb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) dev_err(info->dev, "Virtual framebuffer alloc failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) memset(new_fb, 0xff, new_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) if (info->screen_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) memcpy(new_fb, old_fb, old_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) dlfb_deferred_vfree(dlfb, (void __force *)info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) info->screen_base = (char __iomem *)new_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) info->fix.smem_len = new_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) info->fix.smem_start = (unsigned long) new_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) info->flags = udlfb_info_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) * Second framebuffer copy to mirror the framebuffer state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) * on the physical USB device. We can function without this.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) * But with imperfect damage info we may send pixels over USB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) * that were, in fact, unchanged - wasting limited USB bandwidth
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) if (shadow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) new_back = vzalloc(new_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) if (!new_back)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) dev_info(info->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) "No shadow/backing buffer allocated\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) dlfb_deferred_vfree(dlfb, dlfb->backing_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) dlfb->backing_buffer = new_back;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) * 1) Get EDID from hw, or use sw default
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) * 2) Parse into various fb_info structs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) * 3) Allocate virtual framebuffer memory to back highest res mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) * Parses EDID into three places used by various parts of fbdev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) * fb_var_screeninfo contains the timing of the monitor's preferred mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) * fb_info.modelist is a linked list of all monitor & VESA modes which work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) * If EDID is not readable/valid, then modelist is all VESA modes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) * Returns 0 if successful
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) static int dlfb_setup_modes(struct dlfb_data *dlfb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) char *default_edid, size_t default_edid_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) char *edid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) int i, result = 0, tries = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) struct device *dev = info->device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) struct fb_videomode *mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) const struct fb_videomode *default_vmode = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) if (info->dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) /* only use mutex if info has been registered */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) mutex_lock(&info->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) /* parent device is used otherwise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) dev = info->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) if (!edid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) result = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) fb_destroy_modelist(&info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) memset(&info->monspecs, 0, sizeof(info->monspecs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) * Try to (re)read EDID from hardware first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) * EDID data may return, but not parse as valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) * Try again a few times, in case of e.g. analog cable noise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) while (tries--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) i = dlfb_get_edid(dlfb, edid, EDID_LENGTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) if (i >= EDID_LENGTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) fb_edid_to_monspecs(edid, &info->monspecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) if (info->monspecs.modedb_len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) dlfb->edid = edid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) dlfb->edid_size = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) /* If that fails, use a previously returned EDID if available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) if (info->monspecs.modedb_len == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) dev_err(dev, "Unable to get valid EDID from device/display\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) if (dlfb->edid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) fb_edid_to_monspecs(dlfb->edid, &info->monspecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) if (info->monspecs.modedb_len > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) dev_err(dev, "Using previously queried EDID\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) /* If that fails, use the default EDID we were handed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) if (info->monspecs.modedb_len == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) if (default_edid_size >= EDID_LENGTH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) fb_edid_to_monspecs(default_edid, &info->monspecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) if (info->monspecs.modedb_len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) memcpy(edid, default_edid, default_edid_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) dlfb->edid = edid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) dlfb->edid_size = default_edid_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) dev_err(dev, "Using default/backup EDID\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) /* If we've got modes, let's pick a best default mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) if (info->monspecs.modedb_len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) for (i = 0; i < info->monspecs.modedb_len; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) mode = &info->monspecs.modedb[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) if (dlfb_is_valid_mode(mode, dlfb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) fb_add_videomode(mode, &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) dev_dbg(dev, "Specified mode %dx%d too big\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) mode->xres, mode->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) if (i == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) /* if we've removed top/best mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) info->monspecs.misc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) &= ~FB_MISC_1ST_DETAIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) default_vmode = fb_find_best_display(&info->monspecs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) /* If everything else has failed, fall back to safe default mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) if (default_vmode == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) struct fb_videomode fb_vmode = {0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) * Add the standard VESA modes to our modelist
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) * Since we don't have EDID, there may be modes that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) * overspec monitor and/or are incorrect aspect ratio, etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) * But at least the user has a chance to choose
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) for (i = 0; i < VESA_MODEDB_SIZE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) mode = (struct fb_videomode *)&vesa_modes[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) if (dlfb_is_valid_mode(mode, dlfb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) fb_add_videomode(mode, &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) dev_dbg(dev, "VESA mode %dx%d too big\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) mode->xres, mode->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) * default to resolution safe for projectors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) * (since they are most common case without EDID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) fb_vmode.xres = 800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) fb_vmode.yres = 600;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) fb_vmode.refresh = 60;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) default_vmode = fb_find_nearest_mode(&fb_vmode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) /* If we have good mode and no active clients*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) if ((default_vmode != NULL) && (dlfb->fb_count == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) fb_videomode_to_var(&info->var, default_vmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) dlfb_var_color_format(&info->var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) * with mode size info, we can now alloc our framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) memcpy(&info->fix, &dlfb_fix, sizeof(dlfb_fix));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) result = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) if (edid && (dlfb->edid != edid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) kfree(edid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) if (info->dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) mutex_unlock(&info->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) struct device_attribute *a, char *buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) struct fb_info *fb_info = dev_get_drvdata(fbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) struct dlfb_data *dlfb = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) return sysfs_emit(buf, "%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) atomic_read(&dlfb->bytes_rendered));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) static ssize_t metrics_bytes_identical_show(struct device *fbdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) struct device_attribute *a, char *buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) struct fb_info *fb_info = dev_get_drvdata(fbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) struct dlfb_data *dlfb = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) return sysfs_emit(buf, "%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) atomic_read(&dlfb->bytes_identical));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) static ssize_t metrics_bytes_sent_show(struct device *fbdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) struct device_attribute *a, char *buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) struct fb_info *fb_info = dev_get_drvdata(fbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) struct dlfb_data *dlfb = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) return sysfs_emit(buf, "%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) atomic_read(&dlfb->bytes_sent));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) struct device_attribute *a, char *buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) struct fb_info *fb_info = dev_get_drvdata(fbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) struct dlfb_data *dlfb = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) return sysfs_emit(buf, "%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) atomic_read(&dlfb->cpu_kcycles_used));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) static ssize_t edid_show(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) struct file *filp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) struct kobject *kobj, struct bin_attribute *a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) char *buf, loff_t off, size_t count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) struct device *fbdev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) struct fb_info *fb_info = dev_get_drvdata(fbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) struct dlfb_data *dlfb = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) if (dlfb->edid == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) if ((off >= dlfb->edid_size) || (count > dlfb->edid_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) if (off + count > dlfb->edid_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) count = dlfb->edid_size - off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) memcpy(buf, dlfb->edid, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) static ssize_t edid_store(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) struct file *filp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) struct kobject *kobj, struct bin_attribute *a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) char *src, loff_t src_off, size_t src_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) struct device *fbdev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) struct fb_info *fb_info = dev_get_drvdata(fbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) struct dlfb_data *dlfb = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) /* We only support write of entire EDID at once, no offset*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) if ((src_size != EDID_LENGTH) || (src_off != 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) ret = dlfb_setup_modes(dlfb, fb_info, src, src_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) if (!dlfb->edid || memcmp(src, dlfb->edid, src_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) ret = dlfb_ops_set_par(fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) return src_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) static ssize_t metrics_reset_store(struct device *fbdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) struct fb_info *fb_info = dev_get_drvdata(fbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) struct dlfb_data *dlfb = fb_info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) atomic_set(&dlfb->bytes_rendered, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) atomic_set(&dlfb->bytes_identical, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) atomic_set(&dlfb->bytes_sent, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) atomic_set(&dlfb->cpu_kcycles_used, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) static const struct bin_attribute edid_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) .attr.name = "edid",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) .attr.mode = 0666,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) .size = EDID_LENGTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) .read = edid_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) .write = edid_store
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) static const struct device_attribute fb_device_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) __ATTR_RO(metrics_bytes_rendered),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) __ATTR_RO(metrics_bytes_identical),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) __ATTR_RO(metrics_bytes_sent),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) __ATTR_RO(metrics_cpu_kcycles_used),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) __ATTR(metrics_reset, S_IWUSR, NULL, metrics_reset_store),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) * This is necessary before we can communicate with the display controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) static int dlfb_select_std_channel(struct dlfb_data *dlfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) void *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) static const u8 set_def_chn[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) 0x57, 0xCD, 0xDC, 0xA7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) 0x1C, 0x88, 0x5E, 0x15,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) 0x60, 0xFE, 0xC6, 0x97,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) 0x16, 0x3D, 0x47, 0xF2 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) buf = kmemdup(set_def_chn, sizeof(set_def_chn), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) ret = usb_control_msg(dlfb->udev, usb_sndctrlpipe(dlfb->udev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) NR_USB_REQUEST_CHANNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) buf, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) static int dlfb_parse_vendor_descriptor(struct dlfb_data *dlfb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) char *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) char *desc_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) int total_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) desc = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) total_len = usb_get_descriptor(interface_to_usbdev(intf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) 0x5f, /* vendor specific */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) 0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) /* if not found, look in configuration descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) if (total_len < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) if (0 == usb_get_extra_descriptor(intf->cur_altsetting,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) 0x5f, &desc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) total_len = (int) desc[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) if (total_len > 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) dev_info(&intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) "vendor descriptor length: %d data: %11ph\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) total_len, desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) if ((desc[0] != total_len) || /* descriptor length */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) (desc[1] != 0x5f) || /* vendor descriptor type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) (desc[2] != 0x01) || /* version (2 bytes) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) (desc[3] != 0x00) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) (desc[4] != total_len - 2)) /* length after type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) goto unrecognized;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) desc_end = desc + total_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) desc += 5; /* the fixed header we've already parsed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) while (desc < desc_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) u8 length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) u16 key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) key = *desc++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) key |= (u16)*desc++ << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) length = *desc++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) switch (key) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) case 0x0200: { /* max_area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) u32 max_area = *desc++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) max_area |= (u32)*desc++ << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) max_area |= (u32)*desc++ << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) max_area |= (u32)*desc++ << 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) dev_warn(&intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) "DL chip limited to %d pixel modes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) max_area);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) dlfb->sku_pixel_limit = max_area;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) desc += length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) dev_info(&intf->dev, "vendor descriptor not available (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) total_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) goto success;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) unrecognized:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) /* allow udlfb to load for now even if firmware unrecognized */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) dev_err(&intf->dev, "Unrecognized vendor firmware descriptor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) success:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) static int dlfb_usb_probe(struct usb_interface *intf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) const struct usb_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) const struct device_attribute *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) struct dlfb_data *dlfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) int retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) struct usb_device *usbdev = interface_to_usbdev(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) /* usb initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) dlfb = kzalloc(sizeof(*dlfb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) if (!dlfb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) dev_err(&intf->dev, "%s: failed to allocate dlfb\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) INIT_LIST_HEAD(&dlfb->deferred_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) dlfb->udev = usb_get_dev(usbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) usb_set_intfdata(intf, dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) dev_dbg(&intf->dev, "console enable=%d\n", console);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) dev_dbg(&intf->dev, "fb_defio enable=%d\n", fb_defio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) dev_dbg(&intf->dev, "shadow enable=%d\n", shadow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) dlfb->sku_pixel_limit = 2048 * 1152; /* default to maximum */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) if (!dlfb_parse_vendor_descriptor(dlfb, intf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) dev_err(&intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) "firmware not recognized, incompatible device?\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) if (pixel_limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) dev_warn(&intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) "DL chip limit of %d overridden to %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) dlfb->sku_pixel_limit, pixel_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) dlfb->sku_pixel_limit = pixel_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) /* allocates framebuffer driver structure, not framebuffer memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) info = framebuffer_alloc(0, &dlfb->udev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) dlfb->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) info->par = dlfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) info->pseudo_palette = dlfb->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) dlfb->ops = dlfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) info->fbops = &dlfb->ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) mutex_init(&dlfb->render_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) dlfb_init_damage(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) spin_lock_init(&dlfb->damage_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) INIT_WORK(&dlfb->damage_work, dlfb_damage_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) INIT_LIST_HEAD(&info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) if (!dlfb_alloc_urb_list(dlfb, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) dev_err(&intf->dev, "unable to allocate urb list\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) /* We don't register a new USB class. Our client interface is dlfbev */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) retval = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) dev_err(info->device, "cmap allocation failed: %d\n", retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) retval = dlfb_setup_modes(dlfb, info, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) if (retval != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) dev_err(info->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) "unable to find common mode for display and adapter\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) /* ready to begin using device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) atomic_set(&dlfb->usb_active, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) dlfb_select_std_channel(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) dlfb_ops_check_var(&info->var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) retval = dlfb_ops_set_par(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) retval = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) dev_err(info->device, "unable to register framebuffer: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) attr = &fb_device_attrs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) retval = device_create_file(info->dev, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) dev_warn(info->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) "failed to create '%s' attribute: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) attr->attr.name, retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) retval = device_create_bin_file(info->dev, &edid_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) dev_warn(info->device, "failed to create '%s' attribute: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) edid_attr.attr.name, retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) dev_info(info->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) "%s is DisplayLink USB device (%dx%d, %dK framebuffer memory)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) dev_name(info->dev), info->var.xres, info->var.yres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) ((dlfb->backing_buffer) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) if (dlfb->info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) dlfb_ops_destroy(dlfb->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) usb_put_dev(dlfb->udev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) kfree(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) static void dlfb_usb_disconnect(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) struct dlfb_data *dlfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) dlfb = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) info = dlfb->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) dev_dbg(&intf->dev, "USB disconnect starting\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) /* we virtualize until all fb clients release. Then we free */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) dlfb->virtualized = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) /* When non-active we'll update virtual framebuffer, but no new urbs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) atomic_set(&dlfb->usb_active, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) /* this function will wait for all in-flight urbs to complete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) dlfb_free_urb_list(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) /* remove udlfb's sysfs interfaces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) device_remove_file(info->dev, &fb_device_attrs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) device_remove_bin_file(info->dev, &edid_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) static struct usb_driver dlfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) .name = "udlfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) .probe = dlfb_usb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) .disconnect = dlfb_usb_disconnect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) .id_table = id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) module_usb_driver(dlfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) static void dlfb_urb_completion(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) struct urb_node *unode = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) struct dlfb_data *dlfb = unode->dlfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) switch (urb->status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) /* success */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) case -ECONNRESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) case -ENOENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) case -ESHUTDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) /* sync/async unlink faults aren't errors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) dev_err(&dlfb->udev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) "%s - nonzero write bulk status received: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) __func__, urb->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) atomic_set(&dlfb->lost_pixels, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) urb->transfer_buffer_length = dlfb->urbs.size; /* reset to actual */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) spin_lock_irqsave(&dlfb->urbs.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) list_add_tail(&unode->entry, &dlfb->urbs.list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) dlfb->urbs.available++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) spin_unlock_irqrestore(&dlfb->urbs.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) up(&dlfb->urbs.limit_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) static void dlfb_free_urb_list(struct dlfb_data *dlfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) int count = dlfb->urbs.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) struct list_head *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) struct urb_node *unode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) struct urb *urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) /* keep waiting and freeing, until we've got 'em all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) while (count--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) down(&dlfb->urbs.limit_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) spin_lock_irq(&dlfb->urbs.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) node = dlfb->urbs.list.next; /* have reserved one with sem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) list_del_init(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) spin_unlock_irq(&dlfb->urbs.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) unode = list_entry(node, struct urb_node, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) urb = unode->urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) /* Free each separately allocated piece */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) usb_free_coherent(urb->dev, dlfb->urbs.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) urb->transfer_buffer, urb->transfer_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) usb_free_urb(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) kfree(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) dlfb->urbs.count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) struct urb *urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) struct urb_node *unode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) size_t wanted_size = count * size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) spin_lock_init(&dlfb->urbs.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) dlfb->urbs.size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) INIT_LIST_HEAD(&dlfb->urbs.list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) sema_init(&dlfb->urbs.limit_sem, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) dlfb->urbs.count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) dlfb->urbs.available = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) while (dlfb->urbs.count * size < wanted_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) unode = kzalloc(sizeof(*unode), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) if (!unode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) unode->dlfb = dlfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) urb = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) if (!urb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) kfree(unode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) unode->urb = urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) buf = usb_alloc_coherent(dlfb->udev, size, GFP_KERNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) &urb->transfer_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) if (!buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) kfree(unode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) usb_free_urb(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) if (size > PAGE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) size /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) dlfb_free_urb_list(dlfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) /* urb->transfer_buffer_length set to actual before submit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) usb_fill_bulk_urb(urb, dlfb->udev, usb_sndbulkpipe(dlfb->udev, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) buf, size, dlfb_urb_completion, unode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) list_add_tail(&unode->entry, &dlfb->urbs.list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) up(&dlfb->urbs.limit_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) dlfb->urbs.count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) dlfb->urbs.available++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) return dlfb->urbs.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) static struct urb *dlfb_get_urb(struct dlfb_data *dlfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) struct list_head *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) struct urb_node *unode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) /* Wait for an in-flight buffer to complete and get re-queued */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) ret = down_timeout(&dlfb->urbs.limit_sem, GET_URB_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) atomic_set(&dlfb->lost_pixels, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) dev_warn(&dlfb->udev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) "wait for urb interrupted: %d available: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) ret, dlfb->urbs.available);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) spin_lock_irq(&dlfb->urbs.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) BUG_ON(list_empty(&dlfb->urbs.list)); /* reserved one with limit_sem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) entry = dlfb->urbs.list.next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) list_del_init(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) dlfb->urbs.available--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) spin_unlock_irq(&dlfb->urbs.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) unode = list_entry(entry, struct urb_node, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) return unode->urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) static int dlfb_submit_urb(struct dlfb_data *dlfb, struct urb *urb, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) BUG_ON(len > dlfb->urbs.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) urb->transfer_buffer_length = len; /* set to actual payload len */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) ret = usb_submit_urb(urb, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) dlfb_urb_completion(urb); /* because no one else will */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) atomic_set(&dlfb->lost_pixels, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) dev_err(&dlfb->udev->dev, "submit urb error: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) MODULE_PARM_DESC(console, "Allow fbcon to open framebuffer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) MODULE_PARM_DESC(fb_defio, "Page fault detection of mmap writes");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) module_param(pixel_limit, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) MODULE_PARM_DESC(pixel_limit, "Force limit on max mode (in x*y pixels)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) "Jaya Kumar <jayakumar.lkml@gmail.com>, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) "Bernie Thompson <bernie@plugable.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995)