summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-15 08:37:45 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-15 08:37:45 -0700
commitafac4c66d1aa6396ce44d94fe895d7b61e085fd4 (patch)
tree57a5e3b6b5c9aa63ba746a366224e3b605c804ca /drivers
parent00c6649bafef628955569dd39a59e3170e48f7b5 (diff)
parenta31e4518bec70333a0a98f2946a12b53b45fe5b9 (diff)
Merge tag 'fbdev-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev
Pull fbdev updates from Helge Deller: "A major refactorization by Thomas Zimmermann from SUSE regarding handling of console font data, addition of helpers for console font rotation and split into individual components for glyphs, fonts and the overall fbcon state. And there is the round of usual code cleanups and fixes: Cleanups: - atyfb: Remove unused fb_list (Geert Uytterhoeven) - goldfishfb, wmt_ge_rops: use devm_platform_ioremap_resource() (Amin GATTOUT) - matroxfb: Mark variable with __maybe_unused (Andy Shevchenko) - omapfb: Add missing error check for clk_get() (Chen Ni) - tdfxfb: Make the VGA register initialisation a bit more obvious (Daniel Palmer) - macfb: Replace deprecated strcpy with strscpy (Thorsten Blum) Fixes: - tdfxfb, udlfb: avoid divide-by-zero on FBIOPUT_VSCREENINFO (Greg Kroah-Hartman) - omap2: fix inconsistent lock returns in omapfb_mmap (Hongling Zeng) - viafb: check ioremap return value in viafb_lcd_get_mobile_state (Wang Jun)" * tag 'fbdev-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev: (40 commits) fbdev: udlfb: avoid divide-by-zero on FBIOPUT_VSCREENINFO fbdev: tdfxfb: avoid divide-by-zero on FBIOPUT_VSCREENINFO fbdev: omap2: fix inconsistent lock returns in omapfb_mmap MAINTAINERS: Add dedicated entry for fbcon fbcon: Put font-rotation state into separate struct fbcon: Fill cursor mask in helper function lib/fonts: Implement font rotation lib/fonts: Refactor glyph-rotation helpers lib/fonts: Refactor glyph-pattern helpers lib/fonts: Implement glyph rotation lib/fonts: Clean up Makefile lib/fonts: Provide helpers for calculating glyph pitch and size vt: Implement helpers for struct vc_font in source file fbcon: Avoid OOB font access if console rotation fails fbdev: atyfb: Remove unused fb_list fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build break fbdev: update help text for CONFIG_FB_NVIDIA fbdev: omapfb: Add missing error check for clk_get() fbdev: viafb: check ioremap return value in viafb_lcd_get_mobile_state lib/fonts: Remove internal symbols and macros from public header file ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/vt/vt.c34
-rw-r--r--drivers/video/console/newport_con.c61
-rw-r--r--drivers/video/fbdev/Kconfig10
-rw-r--r--drivers/video/fbdev/aty/atyfb_base.c4
-rw-r--r--drivers/video/fbdev/core/bitblit.c46
-rw-r--r--drivers/video/fbdev/core/fb_defio.c266
-rw-r--r--drivers/video/fbdev/core/fbcon.c242
-rw-r--r--drivers/video/fbdev/core/fbcon.h18
-rw-r--r--drivers/video/fbdev/core/fbcon_ccw.c70
-rw-r--r--drivers/video/fbdev/core/fbcon_cw.c70
-rw-r--r--drivers/video/fbdev/core/fbcon_rotate.c88
-rw-r--r--drivers/video/fbdev/core/fbcon_rotate.h71
-rw-r--r--drivers/video/fbdev/core/fbcon_ud.c67
-rw-r--r--drivers/video/fbdev/core/fbmem.c6
-rw-r--r--drivers/video/fbdev/goldfishfb.c14
-rw-r--r--drivers/video/fbdev/macfb.c38
-rw-r--r--drivers/video/fbdev/matrox/g450_pll.c2
-rw-r--r--drivers/video/fbdev/omap/hwa742.c4
-rw-r--r--drivers/video/fbdev/omap2/omapfb/omapfb-main.c2
-rw-r--r--drivers/video/fbdev/tdfxfb.c112
-rw-r--r--drivers/video/fbdev/udlfb.c3
-rw-r--r--drivers/video/fbdev/via/lcd.c3
-rw-r--r--drivers/video/fbdev/wmt_ge_rops.c18
23 files changed, 554 insertions, 695 deletions
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index b4b19157f05c..8470aaf00531 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -231,6 +231,40 @@ enum {
};
/*
+ * struct vc_font
+ */
+
+/**
+ * vc_font_pitch - Calculates the number of bytes between two adjacent scanlines
+ * @font: The VC font
+ *
+ * Returns:
+ * The number of bytes between two adjacent scanlines in the font data
+ */
+unsigned int vc_font_pitch(const struct vc_font *font)
+{
+ return font_glyph_pitch(font->width);
+}
+EXPORT_SYMBOL_GPL(vc_font_pitch);
+
+/**
+ * vc_font_size - Calculates the size of the font data in bytes
+ * @font: The VC font
+ *
+ * vc_font_size() calculates the number of bytes of font data in the
+ * font specified by @font. The function calculates the size from the
+ * font parameters.
+ *
+ * Returns:
+ * The size of the font data in bytes.
+ */
+unsigned int vc_font_size(const struct vc_font *font)
+{
+ return font_glyph_size(font->width, font->height) * font->charcount;
+}
+EXPORT_SYMBOL_GPL(vc_font_size);
+
+/*
* /sys/class/tty/tty0/
*
* the attribute 'active' contains the name of the current vc
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 337e04236d6d..e88ff3a93b77 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -33,9 +33,9 @@
#define NEWPORT_LEN 0x10000
-#define FONT_DATA ((unsigned char *)font_vga_8x16.data)
+#define FONT_DATA font_vga_8x16.data
-static unsigned char *font_data[MAX_NR_CONSOLES];
+static font_data_t *font_data[MAX_NR_CONSOLES];
static struct newport_regs *npregs;
static unsigned long newport_addr;
@@ -370,9 +370,9 @@ static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
static void newport_putc(struct vc_data *vc, u16 charattr, unsigned int ypos,
unsigned int xpos)
{
- unsigned char *p;
+ const unsigned char *p;
- p = &font_data[vc->vc_num][(charattr & 0xff) << 4];
+ p = &font_data_buf(font_data[vc->vc_num])[(charattr & 0xff) << 4];
charattr = (charattr >> 8) & 0xff;
xpos <<= 3;
ypos <<= 4;
@@ -400,7 +400,7 @@ static void newport_putcs(struct vc_data *vc, const u16 *s,
unsigned int count, unsigned int ypos,
unsigned int xpos)
{
- unsigned char *p;
+ const unsigned char *p;
unsigned int i;
u16 charattr;
@@ -424,7 +424,7 @@ static void newport_putcs(struct vc_data *vc, const u16 *s,
NPORT_DMODE0_L32);
for (i = 0; i < count; i++, xpos += 8) {
- p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4];
+ p = &font_data_buf(font_data[vc->vc_num])[(scr_readw(s++) & 0xff) << 4];
newport_wait(npregs);
@@ -501,52 +501,32 @@ static int newport_set_font(int unit, const struct console_font *op,
{
int w = op->width;
int h = op->height;
- int size = h * op->charcount;
int i;
- unsigned char *new_data, *data = op->data, *p;
+ font_data_t *new_data;
/* ladis: when I grow up, there will be a day... and more sizes will
* be supported ;-) */
- if ((w != 8) || (h != 16) || (vpitch != 32)
- || (op->charcount != 256 && op->charcount != 512))
+ if (w != 8 || h != 16 || (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
- if (!(new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size,
- GFP_USER))) return -ENOMEM;
-
- new_data += FONT_EXTRA_WORDS * sizeof(int);
- FNTSIZE(new_data) = size;
- FNTCHARCNT(new_data) = op->charcount;
- REFCOUNT(new_data) = 0; /* usage counter */
- FNTSUM(new_data) = 0;
-
- p = new_data;
- for (i = 0; i < op->charcount; i++) {
- memcpy(p, data, h);
- data += 32;
- p += h;
- }
+ new_data = font_data_import(op, vpitch, NULL);
+ if (IS_ERR(new_data))
+ return PTR_ERR(new_data);
/* check if font is already used by other console */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
- if (font_data[i] != FONT_DATA
- && FNTSIZE(font_data[i]) == size
- && !memcmp(font_data[i], new_data, size)) {
- kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
+ if (font_data_is_equal(font_data[i], new_data)) {
+ font_data_put(new_data);
/* current font is the same as the new one */
if (i == unit)
return 0;
new_data = font_data[i];
+ font_data_get(new_data);
break;
}
}
- /* old font is user font */
- if (font_data[unit] != FONT_DATA) {
- if (--REFCOUNT(font_data[unit]) == 0)
- kfree(font_data[unit] -
- FONT_EXTRA_WORDS * sizeof(int));
- }
- REFCOUNT(new_data)++;
+
+ font_data_put(font_data[unit]);
font_data[unit] = new_data;
return 0;
@@ -554,12 +534,9 @@ static int newport_set_font(int unit, const struct console_font *op,
static int newport_set_def_font(int unit, struct console_font *op)
{
- if (font_data[unit] != FONT_DATA) {
- if (--REFCOUNT(font_data[unit]) == 0)
- kfree(font_data[unit] -
- FONT_EXTRA_WORDS * sizeof(int));
- font_data[unit] = FONT_DATA;
- }
+ font_data_put(font_data[unit]);
+ font_data[unit] = FONT_DATA;
+ font_data_get(font_data[unit]);
return 0;
}
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index ac9ac4287c6a..1c73d560f196 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -668,10 +668,12 @@ config FB_NVIDIA
select BITREVERSE
select VGASTATE
help
- This driver supports graphics boards with the nVidia chips, TNT
- and newer. For very old chipsets, such as the RIVA128, then use
- the rivafb.
- Say Y if you have such a graphics board.
+ This driver supports graphics boards with the nVidia chips, from TNT
+ through early GeForce generations (NV4–NV2x: Twintor, Twintor2, Celsius,
+ Kelvin).
+ Later architectures (Rankine and newer) are not reliably supported.
+ For very old chipsets, such as the RIVA128, use rivafb.
+ If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called nvidiafb.
diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index d5e107730a4d..9fc5af09f86c 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -2324,8 +2324,6 @@ static void aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
* Initialisation
*/
-static struct fb_info *fb_list = NULL;
-
#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)
static int atyfb_get_timings_from_lcd(struct atyfb_par *par,
struct fb_var_screeninfo *var)
@@ -2758,8 +2756,6 @@ static int aty_init(struct fb_info *info)
#endif
}
- fb_list = info;
-
PRINTKI("fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, par->bus_type == ISA ? "ISA" : "PCI");
return 0;
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 085ffb44c51a..65681dcc5930 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -22,8 +22,7 @@
/*
* Accelerated handlers.
*/
-static void update_attr(u8 *dst, u8 *src, int attribute,
- struct vc_data *vc)
+static void update_attr(u8 *dst, const u8 *src, int attribute, struct vc_data *vc)
{
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = DIV_ROUND_UP(vc->vc_font.width, 8);
@@ -81,7 +80,7 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
unsigned int charcnt = vc->vc_font.charcount;
u32 idx = vc->vc_font.width >> 3;
- u8 *src;
+ const u8 *src;
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
@@ -120,7 +119,7 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
u32 shift_low = 0, mod = vc->vc_font.width % 8;
u32 shift_high = 8;
u32 idx = vc->vc_font.width >> 3;
- u8 *src;
+ const u8 *src;
while (cnt--) {
u16 ch = scr_readw(s++) & charmask;
@@ -267,7 +266,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1;
- char *src;
+ const u8 *src;
cursor.set = 0;
@@ -278,7 +277,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
attribute = get_attribute(info, c);
src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
- if (par->cursor_state.image.data != src ||
+ if (par->cursor_state.image.data != (const char *)src ||
par->cursor_reset) {
par->cursor_state.image.data = src;
cursor.set |= FB_CUR_SETIMAGE;
@@ -330,46 +329,17 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
vc->vc_cursor_type != par->p->cursor_shape ||
par->cursor_state.mask == NULL ||
par->cursor_reset) {
- char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
- int cur_height, size, i = 0;
- u8 msk = 0xff;
+ unsigned char *mask = kmalloc_array(vc->vc_font.height, w, GFP_ATOMIC);
if (!mask)
return;
+ fbcon_fill_cursor_mask(par, vc, mask);
kfree(par->cursor_state.mask);
- par->cursor_state.mask = mask;
+ par->cursor_state.mask = (const char *)mask;
par->p->cursor_shape = vc->vc_cursor_type;
cursor.set |= FB_CUR_SETSHAPE;
-
- switch (CUR_SIZE(par->p->cursor_shape)) {
- case CUR_NONE:
- cur_height = 0;
- break;
- case CUR_UNDERLINE:
- cur_height = (vc->vc_font.height < 10) ? 1 : 2;
- break;
- case CUR_LOWER_THIRD:
- cur_height = vc->vc_font.height/3;
- break;
- case CUR_LOWER_HALF:
- cur_height = vc->vc_font.height >> 1;
- break;
- case CUR_TWO_THIRDS:
- cur_height = (vc->vc_font.height << 1)/3;
- break;
- case CUR_BLOCK:
- default:
- cur_height = vc->vc_font.height;
- break;
- }
- size = (vc->vc_font.height - cur_height) * w;
- while (size--)
- mask[i++] = ~msk;
- size = cur_height * w;
- while (size--)
- mask[i++] = msk;
}
par->cursor_state.enable = enable && !use_sw;
diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
index ca48b89a323d..a12dd25ab697 100644
--- a/drivers/video/fbdev/core/fb_defio.c
+++ b/drivers/video/fbdev/core/fb_defio.c
@@ -14,6 +14,7 @@
#include <linux/export.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -24,6 +25,104 @@
#include <linux/rmap.h>
#include <linux/pagemap.h>
+struct address_space;
+
+/*
+ * struct fb_deferred_io_state
+ */
+
+struct fb_deferred_io_state {
+ struct kref ref;
+
+ int open_count; /* number of opened files; protected by fb_info lock */
+ struct address_space *mapping; /* page cache object for fb device */
+
+ struct mutex lock; /* mutex that protects the pageref list */
+ /* fields protected by lock */
+ struct fb_info *info;
+ struct list_head pagereflist; /* list of pagerefs for touched pages */
+ unsigned long npagerefs;
+ struct fb_deferred_io_pageref *pagerefs;
+};
+
+static struct fb_deferred_io_state *fb_deferred_io_state_alloc(unsigned long len)
+{
+ struct fb_deferred_io_state *fbdefio_state;
+ struct fb_deferred_io_pageref *pagerefs;
+ unsigned long npagerefs;
+
+ fbdefio_state = kzalloc_obj(*fbdefio_state);
+ if (!fbdefio_state)
+ return NULL;
+
+ npagerefs = DIV_ROUND_UP(len, PAGE_SIZE);
+
+ /* alloc a page ref for each page of the display memory */
+ pagerefs = kvzalloc_objs(*pagerefs, npagerefs);
+ if (!pagerefs)
+ goto err_kfree;
+ fbdefio_state->npagerefs = npagerefs;
+ fbdefio_state->pagerefs = pagerefs;
+
+ kref_init(&fbdefio_state->ref);
+ mutex_init(&fbdefio_state->lock);
+
+ INIT_LIST_HEAD(&fbdefio_state->pagereflist);
+
+ return fbdefio_state;
+
+err_kfree:
+ kfree(fbdefio_state);
+ return NULL;
+}
+
+static void fb_deferred_io_state_release(struct fb_deferred_io_state *fbdefio_state)
+{
+ WARN_ON(!list_empty(&fbdefio_state->pagereflist));
+ mutex_destroy(&fbdefio_state->lock);
+ kvfree(fbdefio_state->pagerefs);
+
+ kfree(fbdefio_state);
+}
+
+static void fb_deferred_io_state_get(struct fb_deferred_io_state *fbdefio_state)
+{
+ kref_get(&fbdefio_state->ref);
+}
+
+static void __fb_deferred_io_state_release(struct kref *ref)
+{
+ struct fb_deferred_io_state *fbdefio_state =
+ container_of(ref, struct fb_deferred_io_state, ref);
+
+ fb_deferred_io_state_release(fbdefio_state);
+}
+
+static void fb_deferred_io_state_put(struct fb_deferred_io_state *fbdefio_state)
+{
+ kref_put(&fbdefio_state->ref, __fb_deferred_io_state_release);
+}
+
+/*
+ * struct vm_operations_struct
+ */
+
+static void fb_deferred_io_vm_open(struct vm_area_struct *vma)
+{
+ struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data;
+
+ WARN_ON_ONCE(!try_module_get(THIS_MODULE));
+ fb_deferred_io_state_get(fbdefio_state);
+}
+
+static void fb_deferred_io_vm_close(struct vm_area_struct *vma)
+{
+ struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data;
+
+ fb_deferred_io_state_put(fbdefio_state);
+ module_put(THIS_MODULE);
+}
+
static struct page *fb_deferred_io_get_page(struct fb_info *info, unsigned long offs)
{
struct fb_deferred_io *fbdefio = info->fbdefio;
@@ -44,18 +143,19 @@ static struct page *fb_deferred_io_get_page(struct fb_info *info, unsigned long
return page;
}
-static struct fb_deferred_io_pageref *fb_deferred_io_pageref_lookup(struct fb_info *info,
- unsigned long offset,
- struct page *page)
+static struct fb_deferred_io_pageref *
+fb_deferred_io_pageref_lookup(struct fb_deferred_io_state *fbdefio_state, unsigned long offset,
+ struct page *page)
{
+ struct fb_info *info = fbdefio_state->info;
unsigned long pgoff = offset >> PAGE_SHIFT;
struct fb_deferred_io_pageref *pageref;
- if (fb_WARN_ON_ONCE(info, pgoff >= info->npagerefs))
+ if (fb_WARN_ON_ONCE(info, pgoff >= fbdefio_state->npagerefs))
return NULL; /* incorrect allocation size */
/* 1:1 mapping between pageref and page offset */
- pageref = &info->pagerefs[pgoff];
+ pageref = &fbdefio_state->pagerefs[pgoff];
if (pageref->page)
goto out;
@@ -75,10 +175,11 @@ static struct fb_deferred_io_pageref *fb_deferred_io_pageref_get(struct fb_info
struct page *page)
{
struct fb_deferred_io *fbdefio = info->fbdefio;
- struct list_head *pos = &fbdefio->pagereflist;
+ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
+ struct list_head *pos = &fbdefio_state->pagereflist;
struct fb_deferred_io_pageref *pageref, *cur;
- pageref = fb_deferred_io_pageref_lookup(info, offset, page);
+ pageref = fb_deferred_io_pageref_lookup(fbdefio_state, offset, page);
if (!pageref)
return NULL;
@@ -99,7 +200,7 @@ static struct fb_deferred_io_pageref *fb_deferred_io_pageref_get(struct fb_info
* pages. If possible, drivers should try to work with
* unsorted page lists instead.
*/
- list_for_each_entry(cur, &fbdefio->pagereflist, list) {
+ list_for_each_entry(cur, &fbdefio_state->pagereflist, list) {
if (cur->offset > pageref->offset)
break;
}
@@ -121,25 +222,46 @@ static void fb_deferred_io_pageref_put(struct fb_deferred_io_pageref *pageref,
/* this is to find and return the vmalloc-ed fb pages */
static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf)
{
+ struct fb_info *info;
unsigned long offset;
struct page *page;
- struct fb_info *info = vmf->vma->vm_private_data;
+ vm_fault_t ret;
+ struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data;
+
+ mutex_lock(&fbdefio_state->lock);
+
+ info = fbdefio_state->info;
+ if (!info) {
+ ret = VM_FAULT_SIGBUS; /* our device is gone */
+ goto err_mutex_unlock;
+ }
offset = vmf->pgoff << PAGE_SHIFT;
- if (offset >= info->fix.smem_len)
- return VM_FAULT_SIGBUS;
+ if (offset >= info->fix.smem_len) {
+ ret = VM_FAULT_SIGBUS;
+ goto err_mutex_unlock;
+ }
page = fb_deferred_io_get_page(info, offset);
- if (!page)
- return VM_FAULT_SIGBUS;
+ if (!page) {
+ ret = VM_FAULT_SIGBUS;
+ goto err_mutex_unlock;
+ }
if (!vmf->vma->vm_file)
fb_err(info, "no mapping available\n");
- BUG_ON(!info->fbdefio->mapping);
+ fb_WARN_ON_ONCE(info, !fbdefio_state->mapping);
+
+ mutex_unlock(&fbdefio_state->lock);
vmf->page = page;
+
return 0;
+
+err_mutex_unlock:
+ mutex_unlock(&fbdefio_state->lock);
+ return ret;
}
int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync)
@@ -166,15 +288,24 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
* Adds a page to the dirty list. Call this from struct
* vm_operations_struct.page_mkwrite.
*/
-static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long offset,
- struct page *page)
+static vm_fault_t fb_deferred_io_track_page(struct fb_deferred_io_state *fbdefio_state,
+ unsigned long offset, struct page *page)
{
- struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_info *info;
+ struct fb_deferred_io *fbdefio;
struct fb_deferred_io_pageref *pageref;
vm_fault_t ret;
/* protect against the workqueue changing the page list */
- mutex_lock(&fbdefio->lock);
+ mutex_lock(&fbdefio_state->lock);
+
+ info = fbdefio_state->info;
+ if (!info) {
+ ret = VM_FAULT_SIGBUS; /* our device is gone */
+ goto err_mutex_unlock;
+ }
+
+ fbdefio = info->fbdefio;
pageref = fb_deferred_io_pageref_get(info, offset, page);
if (WARN_ON_ONCE(!pageref)) {
@@ -192,50 +323,38 @@ static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long
*/
lock_page(pageref->page);
- mutex_unlock(&fbdefio->lock);
+ mutex_unlock(&fbdefio_state->lock);
/* come back after delay to process the deferred IO */
schedule_delayed_work(&info->deferred_work, fbdefio->delay);
return VM_FAULT_LOCKED;
err_mutex_unlock:
- mutex_unlock(&fbdefio->lock);
+ mutex_unlock(&fbdefio_state->lock);
return ret;
}
-/*
- * fb_deferred_io_page_mkwrite - Mark a page as written for deferred I/O
- * @fb_info: The fbdev info structure
- * @vmf: The VM fault
- *
- * This is a callback we get when userspace first tries to
- * write to the page. We schedule a workqueue. That workqueue
- * will eventually mkclean the touched pages and execute the
- * deferred framebuffer IO. Then if userspace touches a page
- * again, we repeat the same scheme.
- *
- * Returns:
- * VM_FAULT_LOCKED on success, or a VM_FAULT error otherwise.
- */
-static vm_fault_t fb_deferred_io_page_mkwrite(struct fb_info *info, struct vm_fault *vmf)
+static vm_fault_t fb_deferred_io_page_mkwrite(struct fb_deferred_io_state *fbdefio_state,
+ struct vm_fault *vmf)
{
unsigned long offset = vmf->pgoff << PAGE_SHIFT;
struct page *page = vmf->page;
file_update_time(vmf->vma->vm_file);
- return fb_deferred_io_track_page(info, offset, page);
+ return fb_deferred_io_track_page(fbdefio_state, offset, page);
}
-/* vm_ops->page_mkwrite handler */
static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf)
{
- struct fb_info *info = vmf->vma->vm_private_data;
+ struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data;
- return fb_deferred_io_page_mkwrite(info, vmf);
+ return fb_deferred_io_page_mkwrite(fbdefio_state, vmf);
}
static const struct vm_operations_struct fb_deferred_io_vm_ops = {
+ .open = fb_deferred_io_vm_open,
+ .close = fb_deferred_io_vm_close,
.fault = fb_deferred_io_fault,
.page_mkwrite = fb_deferred_io_mkwrite,
};
@@ -248,11 +367,17 @@ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+ if (!try_module_get(THIS_MODULE))
+ return -EINVAL;
+
vma->vm_ops = &fb_deferred_io_vm_ops;
vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
if (!(info->flags & FBINFO_VIRTFB))
vm_flags_set(vma, VM_IO);
- vma->vm_private_data = info;
+ vma->vm_private_data = info->fbdefio_state;
+
+ fb_deferred_io_state_get(info->fbdefio_state); /* released in vma->vm_ops->close() */
+
return 0;
}
EXPORT_SYMBOL_GPL(fb_deferred_io_mmap);
@@ -263,63 +388,52 @@ static void fb_deferred_io_work(struct work_struct *work)
struct fb_info *info = container_of(work, struct fb_info, deferred_work.work);
struct fb_deferred_io_pageref *pageref, *next;
struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
/* here we wrprotect the page's mappings, then do all deferred IO. */
- mutex_lock(&fbdefio->lock);
+ mutex_lock(&fbdefio_state->lock);
#ifdef CONFIG_MMU
- list_for_each_entry(pageref, &fbdefio->pagereflist, list) {
+ list_for_each_entry(pageref, &fbdefio_state->pagereflist, list) {
struct page *page = pageref->page;
pgoff_t pgoff = pageref->offset >> PAGE_SHIFT;
- mapping_wrprotect_range(fbdefio->mapping, pgoff,
+ mapping_wrprotect_range(fbdefio_state->mapping, pgoff,
page_to_pfn(page), 1);
}
#endif
/* driver's callback with pagereflist */
- fbdefio->deferred_io(info, &fbdefio->pagereflist);
+ fbdefio->deferred_io(info, &fbdefio_state->pagereflist);
/* clear the list */
- list_for_each_entry_safe(pageref, next, &fbdefio->pagereflist, list)
+ list_for_each_entry_safe(pageref, next, &fbdefio_state->pagereflist, list)
fb_deferred_io_pageref_put(pageref, info);
- mutex_unlock(&fbdefio->lock);
+ mutex_unlock(&fbdefio_state->lock);
}
int fb_deferred_io_init(struct fb_info *info)
{
struct fb_deferred_io *fbdefio = info->fbdefio;
- struct fb_deferred_io_pageref *pagerefs;
- unsigned long npagerefs;
- int ret;
+ struct fb_deferred_io_state *fbdefio_state;
BUG_ON(!fbdefio);
if (WARN_ON(!info->fix.smem_len))
return -EINVAL;
- mutex_init(&fbdefio->lock);
+ fbdefio_state = fb_deferred_io_state_alloc(info->fix.smem_len);
+ if (!fbdefio_state)
+ return -ENOMEM;
+ fbdefio_state->info = info;
+
INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
- INIT_LIST_HEAD(&fbdefio->pagereflist);
if (fbdefio->delay == 0) /* set a default of 1 s */
fbdefio->delay = HZ;
- npagerefs = DIV_ROUND_UP(info->fix.smem_len, PAGE_SIZE);
-
- /* alloc a page ref for each page of the display memory */
- pagerefs = kvzalloc_objs(*pagerefs, npagerefs);
- if (!pagerefs) {
- ret = -ENOMEM;
- goto err;
- }
- info->npagerefs = npagerefs;
- info->pagerefs = pagerefs;
+ info->fbdefio_state = fbdefio_state;
return 0;
-
-err:
- mutex_destroy(&fbdefio->lock);
- return ret;
}
EXPORT_SYMBOL_GPL(fb_deferred_io_init);
@@ -327,11 +441,11 @@ void fb_deferred_io_open(struct fb_info *info,
struct inode *inode,
struct file *file)
{
- struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
- fbdefio->mapping = file->f_mapping;
+ fbdefio_state->mapping = file->f_mapping;
file->f_mapping->a_ops = &fb_deferred_io_aops;
- fbdefio->open_count++;
+ fbdefio_state->open_count++;
}
EXPORT_SYMBOL_GPL(fb_deferred_io_open);
@@ -342,21 +456,25 @@ static void fb_deferred_io_lastclose(struct fb_info *info)
void fb_deferred_io_release(struct fb_info *info)
{
- struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
- if (!--fbdefio->open_count)
+ if (!--fbdefio_state->open_count)
fb_deferred_io_lastclose(info);
}
EXPORT_SYMBOL_GPL(fb_deferred_io_release);
void fb_deferred_io_cleanup(struct fb_info *info)
{
- struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
fb_deferred_io_lastclose(info);
- kvfree(info->pagerefs);
- mutex_destroy(&fbdefio->lock);
- fbdefio->mapping = NULL;
+ info->fbdefio_state = NULL;
+
+ mutex_lock(&fbdefio_state->lock);
+ fbdefio_state->info = NULL;
+ mutex_unlock(&fbdefio_state->lock);
+
+ fb_deferred_io_state_put(fbdefio_state);
}
EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 666261ae59d8..b0e3e765360d 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -446,6 +446,46 @@ static void fbcon_del_cursor_work(struct fb_info *info)
cancel_delayed_work_sync(&par->cursor_work);
}
+void fbcon_fill_cursor_mask(struct fbcon_par *par, struct vc_data *vc, unsigned char *mask)
+{
+ static const unsigned int pattern = 0xffffffff;
+ unsigned int pitch = vc_font_pitch(&vc->vc_font);
+ unsigned int cur_height, size;
+
+ switch (CUR_SIZE(vc->vc_cursor_type)) {
+ case CUR_NONE:
+ cur_height = 0;
+ break;
+ case CUR_UNDERLINE:
+ if (vc->vc_font.height < 10)
+ cur_height = 1;
+ else
+ cur_height = 2;
+ break;
+ case CUR_LOWER_THIRD:
+ cur_height = vc->vc_font.height / 3;
+ break;
+ case CUR_LOWER_HALF:
+ cur_height = vc->vc_font.height / 2;
+ break;
+ case CUR_TWO_THIRDS:
+ cur_height = (vc->vc_font.height * 2) / 3;
+ break;
+ case CUR_BLOCK:
+ default:
+ cur_height = vc->vc_font.height;
+ break;
+ }
+
+ size = (vc->vc_font.height - cur_height) * pitch;
+ while (size--)
+ *mask++ = (unsigned char)~pattern;
+
+ size = cur_height * pitch;
+ while (size--)
+ *mask++ = (unsigned char)pattern;
+}
+
#ifndef MODULE
static int __init fb_console_setup(char *this_opt)
{
@@ -747,7 +787,9 @@ static void fbcon_release(struct fb_info *info)
kfree(par->cursor_state.mask);
kfree(par->cursor_data);
kfree(par->cursor_src);
- kfree(par->fontbuffer);
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+ kfree(par->rotated.buf);
+#endif
kfree(info->fbcon_par);
info->fbcon_par = NULL;
}
@@ -1000,7 +1042,9 @@ static const char *fbcon_startup(void)
par = info->fbcon_par;
par->currcon = -1;
par->graphics = 1;
- par->cur_rotate = -1;
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+ par->rotated.buf_rotate = -1;
+#endif
p->con_rotate = initial_rotation;
if (p->con_rotate == -1)
@@ -1019,8 +1063,11 @@ static const char *fbcon_startup(void)
info->pixmap.blit_y);
vc->vc_font.width = font->width;
vc->vc_font.height = font->height;
- vc->vc_font.data = (void *)(p->fontdata = font->data);
+ vc->vc_font.data = font_data_buf(font->data);
vc->vc_font.charcount = font->charcount;
+
+ p->fontdata = font->data;
+ font_data_get(p->fontdata);
}
cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
@@ -1078,15 +1125,13 @@ static void fbcon_init(struct vc_data *vc, bool init)
if (t->fontdata) {
struct vc_data *fvc = vc_cons[fg_console].d;
- vc->vc_font.data = (void *)(p->fontdata =
- fvc->vc_font.data);
+ vc->vc_font.data = fvc->vc_font.data;
vc->vc_font.width = fvc->vc_font.width;
vc->vc_font.height = fvc->vc_font.height;
vc->vc_font.charcount = fvc->vc_font.charcount;
- p->userfont = t->userfont;
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
+ p->fontdata = t->fontdata;
+ font_data_get(p->fontdata);
} else {
const struct font_desc *font = NULL;
@@ -1097,8 +1142,11 @@ static void fbcon_init(struct vc_data *vc, bool init)
info->pixmap.blit_y);
vc->vc_font.width = font->width;
vc->vc_font.height = font->height;
- vc->vc_font.data = (void *)(p->fontdata = font->data);
+ vc->vc_font.data = font_data_buf(font->data);
vc->vc_font.charcount = font->charcount;
+
+ p->fontdata = font->data;
+ font_data_get(p->fontdata);
}
}
@@ -1189,10 +1237,10 @@ static void fbcon_init(struct vc_data *vc, bool init)
static void fbcon_free_font(struct fbcon_display *p)
{
- if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
- kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
- p->fontdata = NULL;
- p->userfont = 0;
+ if (p->fontdata) {
+ font_data_put(p->fontdata);
+ p->fontdata = NULL;
+ }
}
static void set_vc_hi_font(struct vc_data *vc, bool set);
@@ -1409,14 +1457,13 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
svc = *default_mode;
t = &fb_display[svc->vc_num];
- if (!vc->vc_font.data) {
- vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
+ if (!p->fontdata) {
+ vc->vc_font.data = font_data_buf(t->fontdata);
vc->vc_font.width = (*default_mode)->vc_font.width;
vc->vc_font.height = (*default_mode)->vc_font.height;
vc->vc_font.charcount = (*default_mode)->vc_font.charcount;
- p->userfont = t->userfont;
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
+ p->fontdata = t->fontdata;
+ font_data_get(p->fontdata);
}
var->activate = FB_ACTIVATE_NOW;
@@ -2036,9 +2083,6 @@ static void updatescrollmode(struct fbcon_display *p,
updatescrollmode_accel(p, info, vc);
}
-#define PITCH(w) (((w) + 7) >> 3)
-#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
-
static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height, bool from_user)
{
@@ -2048,9 +2092,8 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
struct fb_var_screeninfo var = info->var;
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
- if (p->userfont && FNTSIZE(vc->vc_font.data)) {
- int size;
- int pitch = PITCH(vc->vc_font.width);
+ if (font_data_size(p->fontdata)) {
+ unsigned int size = vc_font_size(&vc->vc_font);
/*
* If user font, ensure that a possible change to user font
@@ -2059,10 +2102,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
* charcount can change and cannot be used to determine the
* font data allocated size.
*/
- if (pitch <= 0)
- return -EINVAL;
- size = CALC_FONTSZ(vc->vc_font.height, pitch, vc->vc_font.charcount);
- if (size > FNTSIZE(vc->vc_font.data))
+ if (!size || size > font_data_size(p->fontdata))
return -EINVAL;
}
@@ -2286,67 +2326,15 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
{
- u8 *fontdata = vc->vc_font.data;
- u8 *data = font->data;
- int i, j;
+ const struct fbcon_display *p = &fb_display[vc->vc_num];
font->width = vc->vc_font.width;
font->height = vc->vc_font.height;
if (font->height > vpitch)
return -ENOSPC;
font->charcount = vc->vc_hi_font_mask ? 512 : 256;
- if (!font->data)
- return 0;
-
- if (font->width <= 8) {
- j = vc->vc_font.height;
- if (font->charcount * j > FNTSIZE(fontdata))
- return -EINVAL;
-
- for (i = 0; i < font->charcount; i++) {
- memcpy(data, fontdata, j);
- memset(data + j, 0, vpitch - j);
- data += vpitch;
- fontdata += j;
- }
- } else if (font->width <= 16) {
- j = vc->vc_font.height * 2;
- if (font->charcount * j > FNTSIZE(fontdata))
- return -EINVAL;
-
- for (i = 0; i < font->charcount; i++) {
- memcpy(data, fontdata, j);
- memset(data + j, 0, 2*vpitch - j);
- data += 2*vpitch;
- fontdata += j;
- }
- } else if (font->width <= 24) {
- if (font->charcount * (vc->vc_font.height * sizeof(u32)) > FNTSIZE(fontdata))
- return -EINVAL;
-
- for (i = 0; i < font->charcount; i++) {
- for (j = 0; j < vc->vc_font.height; j++) {
- *data++ = fontdata[0];
- *data++ = fontdata[1];
- *data++ = fontdata[2];
- fontdata += sizeof(u32);
- }
- memset(data, 0, 3 * (vpitch - j));
- data += 3 * (vpitch - j);
- }
- } else {
- j = vc->vc_font.height * 4;
- if (font->charcount * j > FNTSIZE(fontdata))
- return -EINVAL;
- for (i = 0; i < font->charcount; i++) {
- memcpy(data, fontdata, j);
- memset(data + j, 0, 4 * vpitch - j);
- data += 4 * vpitch;
- fontdata += j;
- }
- }
- return 0;
+ return font_data_export(p->fontdata, font, vpitch);
}
/* set/clear vc_hi_font_mask and update vc attrs accordingly */
@@ -2411,20 +2399,20 @@ static void set_vc_hi_font(struct vc_data *vc, bool set)
}
static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
- const u8 * data, int userfont)
+ font_data_t *data)
{
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_par *par = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];
- int resize, ret, old_userfont, old_width, old_height, old_charcount;
- u8 *old_data = vc->vc_font.data;
+ int resize, ret, old_width, old_height, old_charcount;
+ font_data_t *old_fontdata = p->fontdata;
+ const u8 *old_data = vc->vc_font.data;
- resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
- vc->vc_font.data = (void *)(p->fontdata = data);
- old_userfont = p->userfont;
- if ((p->userfont = userfont))
- REFCOUNT(data)++;
+ font_data_get(data);
+ resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
+ p->fontdata = data;
+ vc->vc_font.data = font_data_buf(p->fontdata);
old_width = vc->vc_font.width;
old_height = vc->vc_font.height;
old_charcount = vc->vc_font.charcount;
@@ -2453,24 +2441,20 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
update_screen(vc);
}
- if (old_userfont && (--REFCOUNT(old_data) == 0))
- kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
+ if (old_fontdata)
+ font_data_put(old_fontdata);
+
return 0;
err_out:
- p->fontdata = old_data;
+ p->fontdata = old_fontdata;
vc->vc_font.data = old_data;
-
- if (userfont) {
- p->userfont = old_userfont;
- if (--REFCOUNT(data) == 0)
- kfree(data - FONT_EXTRA_WORDS * sizeof(int));
- }
-
vc->vc_font.width = old_width;
vc->vc_font.height = old_height;
vc->vc_font.charcount = old_charcount;
+ font_data_put(data);
+
return ret;
}
@@ -2486,10 +2470,8 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
unsigned charcount = font->charcount;
int w = font->width;
int h = font->height;
- int size, alloc_size;
- int i, csum;
- u8 *new_data, *data = font->data;
- int pitch = PITCH(font->width);
+ int i, ret;
+ font_data_t *new_data;
/* Is there a reason why fbconsole couldn't handle any charcount >256?
* If not this check should be changed to charcount < 256 */
@@ -2513,50 +2495,24 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
if (fbcon_invalid_charcount(info, charcount))
return -EINVAL;
- /* Check for integer overflow in font size calculation */
- if (check_mul_overflow(h, pitch, &size) ||
- check_mul_overflow(size, charcount, &size))
- return -EINVAL;
-
- /* Check for overflow in allocation size calculation */
- if (check_add_overflow(FONT_EXTRA_WORDS * sizeof(int), size, &alloc_size))
- return -EINVAL;
-
- new_data = kmalloc(alloc_size, GFP_USER);
+ new_data = font_data_import(font, vpitch, crc32);
+ if (IS_ERR(new_data))
+ return PTR_ERR(new_data);
- if (!new_data)
- return -ENOMEM;
-
- memset(new_data, 0, FONT_EXTRA_WORDS * sizeof(int));
-
- new_data += FONT_EXTRA_WORDS * sizeof(int);
- FNTSIZE(new_data) = size;
- REFCOUNT(new_data) = 0; /* usage counter */
- for (i=0; i< charcount; i++) {
- memcpy(new_data + i*h*pitch, data + i*vpitch*pitch, h*pitch);
- }
-
- /* Since linux has a nice crc32 function use it for counting font
- * checksums. */
- csum = crc32(0, new_data, size);
-
- FNTSUM(new_data) = csum;
/* Check if the same font is on some other console already */
for (i = first_fb_vc; i <= last_fb_vc; i++) {
- struct vc_data *tmp = vc_cons[i].d;
-
- if (fb_display[i].userfont &&
- fb_display[i].fontdata &&
- FNTSUM(fb_display[i].fontdata) == csum &&
- FNTSIZE(fb_display[i].fontdata) == size &&
- tmp->vc_font.width == w &&
- !memcmp(fb_display[i].fontdata, new_data, size)) {
- kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
- new_data = (u8 *)fb_display[i].fontdata;
+ if (fb_display[i].fontdata &&
+ font_data_is_equal(fb_display[i].fontdata, new_data)) {
+ font_data_get(fb_display[i].fontdata);
+ font_data_put(new_data);
+ new_data = fb_display[i].fontdata;
break;
}
}
- return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1);
+ ret = fbcon_do_set_font(vc, font->width, font->height, charcount, new_data);
+ font_data_put(new_data);
+
+ return ret;
}
static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font,
@@ -2573,7 +2529,7 @@ static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font,
font->width = f->width;
font->height = f->height;
- return fbcon_do_set_font(vc, f->width, f->height, f->charcount, f->data, 0);
+ return fbcon_do_set_font(vc, f->width, f->height, f->charcount, f->data);
}
static u16 palette_red[16];
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index fca14e9b729b..321cc7f44baa 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -11,6 +11,7 @@
#ifndef _VIDEO_FBCON_H
#define _VIDEO_FBCON_H
+#include <linux/font.h>
#include <linux/types.h>
#include <linux/vt_buffer.h>
#include <linux/vt_kern.h>
@@ -25,8 +26,7 @@
struct fbcon_display {
/* Filled in by the low-level console driver */
- const u_char *fontdata;
- int userfont; /* != 0 if fontdata kmalloc()ed */
+ font_data_t *fontdata;
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
u_short scrollmode; /* Scroll Method, use fb_scrollmode() */
#endif
@@ -80,13 +80,17 @@ struct fbcon_par {
int graphics;
bool initialized;
int rotate;
- int cur_rotate;
char *cursor_data;
- u8 *fontbuffer;
- u8 *fontdata;
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+ struct {
+ font_data_t *fontdata; /* source font */
+ u8 *buf; /* rotated glyphs */
+ size_t bufsize;
+ int buf_rotate; /* rotation of buf */
+ } rotated;
+#endif
u8 *cursor_src;
u32 cursor_size;
- u32 fd_size;
const struct fbcon_bitops *bitops;
};
@@ -192,6 +196,8 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
extern void fbcon_set_bitops_ur(struct fbcon_par *par);
extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
+void fbcon_fill_cursor_mask(struct fbcon_par *par, struct vc_data *vc, unsigned char *mask);
+
#define FBCON_ATTRIBUTE_UNDERLINE 1
#define FBCON_ATTRIBUTE_REVERSE 2
#define FBCON_ATTRIBUTE_BOLD 4
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 2f394b5a17f7..33f02d579e02 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/fb.h>
+#include <linux/font.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
#include <asm/types.h>
@@ -26,7 +27,7 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
- int width = (vc->vc_font.height + 7) >> 3;
+ int width = font_glyph_pitch(vc->vc_font.height);
int mod = vc->vc_font.height % 8;
u8 c, msk = ~(0xff << offset), msk1 = 0;
@@ -101,11 +102,11 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
{
struct fbcon_par *par = info->fbcon_par;
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- u32 idx = (vc->vc_font.height + 7) >> 3;
+ u32 idx = font_glyph_pitch(vc->vc_font.height);
u8 *src;
while (cnt--) {
- src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
+ src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
if (attr) {
ccw_update_attr(buf, src, attr, vc);
@@ -131,7 +132,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
{
struct fb_image image;
struct fbcon_par *par = info->fbcon_par;
- u32 width = (vc->vc_font.height + 7)/8;
+ u32 width = font_glyph_pitch(vc->vc_font.height);
u32 cellsize = width * vc->vc_font.width;
u32 maxcnt = info->pixmap.size/cellsize;
u32 scan_align = info->pixmap.scan_align - 1;
@@ -141,7 +142,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
u8 *dst, *buf = NULL;
u32 vyres = GETVYRES(par->p, info);
- if (!par->fontbuffer)
+ if (!par->rotated.buf)
return;
image.fg_color = fg;
@@ -223,21 +224,22 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
struct fb_cursor cursor;
struct fbcon_par *par = info->fbcon_par;
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- int w = (vc->vc_font.height + 7) >> 3, c;
+ int w = font_glyph_pitch(vc->vc_font.height);
+ int c;
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
u32 vyres = GETVYRES(par->p, info);
- if (!par->fontbuffer)
+ if (!par->rotated.buf)
return;
cursor.set = 0;
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+ src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.width));
if (par->cursor_state.image.data != src ||
par->cursor_reset) {
@@ -294,58 +296,26 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
vc->vc_cursor_type != par->p->cursor_shape ||
par->cursor_state.mask == NULL ||
par->cursor_reset) {
- char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
- GFP_ATOMIC);
- int cur_height, size, i = 0;
- int width = (vc->vc_font.width + 7)/8;
+ unsigned char *tmp, *mask;
- if (!mask)
+ tmp = kmalloc_array(vc->vc_font.height, vc_font_pitch(&vc->vc_font), GFP_ATOMIC);
+ if (!tmp)
return;
+ fbcon_fill_cursor_mask(par, vc, tmp);
- tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC);
-
- if (!tmp) {
- kfree(mask);
+ mask = kmalloc_array(vc->vc_font.width, w, GFP_ATOMIC);
+ if (!mask) {
+ kfree(tmp);
return;
}
+ font_glyph_rotate_270(tmp, vc->vc_font.width, vc->vc_font.height, mask);
+ kfree(tmp);
kfree(par->cursor_state.mask);
- par->cursor_state.mask = mask;
+ par->cursor_state.mask = (const char *)mask;
par->p->cursor_shape = vc->vc_cursor_type;
cursor.set |= FB_CUR_SETSHAPE;
-
- switch (CUR_SIZE(par->p->cursor_shape)) {
- case CUR_NONE:
- cur_height = 0;
- break;
- case CUR_UNDERLINE:
- cur_height = (vc->vc_font.height < 10) ? 1 : 2;
- break;
- case CUR_LOWER_THIRD:
- cur_height = vc->vc_font.height/3;
- break;
- case CUR_LOWER_HALF:
- cur_height = vc->vc_font.height >> 1;
- break;
- case CUR_TWO_THIRDS:
- cur_height = (vc->vc_font.height << 1)/3;
- break;
- case CUR_BLOCK:
- default:
- cur_height = vc->vc_font.height;
- break;
- }
-
- size = (vc->vc_font.height - cur_height) * width;
- while (size--)
- tmp[i++] = 0;
- size = cur_height * width;
- while (size--)
- tmp[i++] = 0xff;
- memset(mask, 0, w * vc->vc_font.width);
- rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
- kfree(tmp);
}
par->cursor_state.enable = enable && !use_sw;
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 3c3ad3471ec4..bde820967eb9 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/fb.h>
+#include <linux/font.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
#include <asm/types.h>
@@ -26,7 +27,7 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
- int width = (vc->vc_font.height + 7) >> 3;
+ int width = font_glyph_pitch(vc->vc_font.height);
u8 c, msk = ~(0xff >> offset);
for (i = 0; i < vc->vc_font.width; i++) {
@@ -86,11 +87,11 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
{
struct fbcon_par *par = info->fbcon_par;
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- u32 idx = (vc->vc_font.height + 7) >> 3;
+ u32 idx = font_glyph_pitch(vc->vc_font.height);
u8 *src;
while (cnt--) {
- src = par->fontbuffer + (scr_readw(s++) & charmask) * cellsize;
+ src = par->rotated.buf + (scr_readw(s++) & charmask) * cellsize;
if (attr) {
cw_update_attr(buf, src, attr, vc);
@@ -116,7 +117,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
{
struct fb_image image;
struct fbcon_par *par = info->fbcon_par;
- u32 width = (vc->vc_font.height + 7)/8;
+ u32 width = font_glyph_pitch(vc->vc_font.height);
u32 cellsize = width * vc->vc_font.width;
u32 maxcnt = info->pixmap.size/cellsize;
u32 scan_align = info->pixmap.scan_align - 1;
@@ -126,7 +127,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
u8 *dst, *buf = NULL;
u32 vxres = GETVXRES(par->p, info);
- if (!par->fontbuffer)
+ if (!par->rotated.buf)
return;
image.fg_color = fg;
@@ -206,21 +207,22 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
struct fb_cursor cursor;
struct fbcon_par *par = info->fbcon_par;
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- int w = (vc->vc_font.height + 7) >> 3, c;
+ int w = font_glyph_pitch(vc->vc_font.height);
+ int c;
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
u32 vxres = GETVXRES(par->p, info);
- if (!par->fontbuffer)
+ if (!par->rotated.buf)
return;
cursor.set = 0;
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+ src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.width));
if (par->cursor_state.image.data != src ||
par->cursor_reset) {
@@ -277,58 +279,26 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
vc->vc_cursor_type != par->p->cursor_shape ||
par->cursor_state.mask == NULL ||
par->cursor_reset) {
- char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
- GFP_ATOMIC);
- int cur_height, size, i = 0;
- int width = (vc->vc_font.width + 7)/8;
+ unsigned char *tmp, *mask;
- if (!mask)
+ tmp = kmalloc_array(vc->vc_font.height, vc_font_pitch(&vc->vc_font), GFP_ATOMIC);
+ if (!tmp)
return;
+ fbcon_fill_cursor_mask(par, vc, tmp);
- tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC);
-
- if (!tmp) {
- kfree(mask);
+ mask = kmalloc_array(vc->vc_font.width, w, GFP_ATOMIC);
+ if (!mask) {
+ kfree(tmp);
return;
}
+ font_glyph_rotate_90(tmp, vc->vc_font.width, vc->vc_font.height, mask);
+ kfree(tmp);
kfree(par->cursor_state.mask);
- par->cursor_state.mask = mask;
+ par->cursor_state.mask = (const char *)mask;
par->p->cursor_shape = vc->vc_cursor_type;
cursor.set |= FB_CUR_SETSHAPE;
-
- switch (CUR_SIZE(par->p->cursor_shape)) {
- case CUR_NONE:
- cur_height = 0;
- break;
- case CUR_UNDERLINE:
- cur_height = (vc->vc_font.height < 10) ? 1 : 2;
- break;
- case CUR_LOWER_THIRD:
- cur_height = vc->vc_font.height/3;
- break;
- case CUR_LOWER_HALF:
- cur_height = vc->vc_font.height >> 1;
- break;
- case CUR_TWO_THIRDS:
- cur_height = (vc->vc_font.height << 1)/3;
- break;
- case CUR_BLOCK:
- default:
- cur_height = vc->vc_font.height;
- break;
- }
-
- size = (vc->vc_font.height - cur_height) * width;
- while (size--)
- tmp[i++] = 0;
- size = cur_height * width;
- while (size--)
- tmp[i++] = 0xff;
- memset(mask, 0, w * vc->vc_font.width);
- rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
- kfree(tmp);
}
par->cursor_state.enable = enable && !use_sw;
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index 1562a8f20b4f..6cdbc96eeca6 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -8,87 +8,45 @@
* more details.
*/
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
+#include <linux/errno.h>
#include <linux/fb.h>
-#include <linux/vt_kern.h>
-#include <linux/console.h>
-#include <asm/types.h>
+#include <linux/font.h>
+
#include "fbcon.h"
#include "fbcon_rotate.h"
int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
{
struct fbcon_par *par = info->fbcon_par;
- int len, err = 0;
- int s_cellsize, d_cellsize, i;
- const u8 *src;
- u8 *dst;
-
- if (vc->vc_font.data == par->fontdata &&
- par->p->con_rotate == par->cur_rotate)
- goto finished;
+ unsigned char *buf;
+ int ret;
- src = par->fontdata = vc->vc_font.data;
- par->cur_rotate = par->p->con_rotate;
- len = vc->vc_font.charcount;
- s_cellsize = ((vc->vc_font.width + 7)/8) *
- vc->vc_font.height;
- d_cellsize = s_cellsize;
+ if (par->p->fontdata == par->rotated.fontdata && par->rotate == par->rotated.buf_rotate)
+ return 0;
- if (par->rotate == FB_ROTATE_CW ||
- par->rotate == FB_ROTATE_CCW)
- d_cellsize = ((vc->vc_font.height + 7)/8) *
- vc->vc_font.width;
+ par->rotated.fontdata = par->p->fontdata;
+ par->rotated.buf_rotate = par->rotate;
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
- if (par->fd_size < d_cellsize * len) {
- dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
-
- if (dst == NULL) {
- err = -ENOMEM;
- goto finished;
- }
-
- par->fd_size = d_cellsize * len;
- kfree(par->fontbuffer);
- par->fontbuffer = dst;
+ buf = font_data_rotate(par->rotated.fontdata, vc->vc_font.width,
+ vc->vc_font.height, vc->vc_font.charcount,
+ par->rotated.buf_rotate, par->rotated.buf,
+ &par->rotated.bufsize);
+ if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
+ goto err_kfree;
}
- dst = par->fontbuffer;
- memset(dst, 0, par->fd_size);
+ par->rotated.buf = buf;
- switch (par->rotate) {
- case FB_ROTATE_UD:
- for (i = len; i--; ) {
- rotate_ud(src, dst, vc->vc_font.width,
- vc->vc_font.height);
+ return 0;
- src += s_cellsize;
- dst += d_cellsize;
- }
- break;
- case FB_ROTATE_CW:
- for (i = len; i--; ) {
- rotate_cw(src, dst, vc->vc_font.width,
- vc->vc_font.height);
- src += s_cellsize;
- dst += d_cellsize;
- }
- break;
- case FB_ROTATE_CCW:
- for (i = len; i--; ) {
- rotate_ccw(src, dst, vc->vc_font.width,
- vc->vc_font.height);
- src += s_cellsize;
- dst += d_cellsize;
- }
- break;
- }
+err_kfree:
+ kfree(par->rotated.buf);
+ par->rotated.buf = NULL; /* clear here to avoid output */
+ par->rotated.bufsize = 0;
-finished:
- return err;
+ return ret;
}
diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h
index 8cb019e8a9c0..725bcae2df61 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.h
+++ b/drivers/video/fbdev/core/fbcon_rotate.h
@@ -19,77 +19,6 @@
(fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
(i)->var.xres : (i)->var.xres_virtual; })
-
-static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
-{
- u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
-
- pat +=index;
- return (*pat) & (0x80 >> bit);
-}
-
-static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
-{
- u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
-
- pat += index;
-
- (*pat) |= 0x80 >> bit;
-}
-
-static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
-{
- int i, j;
- int shift = (8 - (width % 8)) & 7;
-
- width = (width + 7) & ~7;
-
- for (i = 0; i < height; i++) {
- for (j = 0; j < width - shift; j++) {
- if (pattern_test_bit(j, i, width, in))
- pattern_set_bit(width - (1 + j + shift),
- height - (1 + i),
- width, out);
- }
-
- }
-}
-
-static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
-{
- int i, j, h = height, w = width;
- int shift = (8 - (height % 8)) & 7;
-
- width = (width + 7) & ~7;
- height = (height + 7) & ~7;
-
- for (i = 0; i < h; i++) {
- for (j = 0; j < w; j++) {
- if (pattern_test_bit(j, i, width, in))
- pattern_set_bit(height - 1 - i - shift, j,
- height, out);
-
- }
- }
-}
-
-static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
-{
- int i, j, h = height, w = width;
- int shift = (8 - (width % 8)) & 7;
-
- width = (width + 7) & ~7;
- height = (height + 7) & ~7;
-
- for (i = 0; i < h; i++) {
- for (j = 0; j < w; j++) {
- if (pattern_test_bit(j, i, width, in))
- pattern_set_bit(i, width - 1 - j - shift,
- height, out);
- }
- }
-}
-
int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc);
#if defined(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION)
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 6fc30cad5b19..eaf08999e249 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -26,7 +26,7 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
- int width = (vc->vc_font.width + 7) >> 3;
+ int width = font_glyph_pitch(vc->vc_font.width);
unsigned int cellsize = vc->vc_font.height * width;
u8 c;
@@ -92,7 +92,7 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
u8 *src;
while (cnt--) {
- src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
+ src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
if (attr) {
ud_update_attr(buf, src, attr, vc);
@@ -127,7 +127,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
u8 *src;
while (cnt--) {
- src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
+ src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize;
if (attr) {
ud_update_attr(buf, src, attr, vc);
@@ -153,7 +153,7 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
{
struct fb_image image;
struct fbcon_par *par = info->fbcon_par;
- u32 width = (vc->vc_font.width + 7)/8;
+ u32 width = font_glyph_pitch(vc->vc_font.width);
u32 cellsize = width * vc->vc_font.height;
u32 maxcnt = info->pixmap.size/cellsize;
u32 scan_align = info->pixmap.scan_align - 1;
@@ -164,7 +164,7 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
u32 vyres = GETVYRES(par->p, info);
u32 vxres = GETVXRES(par->p, info);
- if (!par->fontbuffer)
+ if (!par->rotated.buf)
return;
image.fg_color = fg;
@@ -253,7 +253,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
struct fb_cursor cursor;
struct fbcon_par *par = info->fbcon_par;
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- int w = (vc->vc_font.width + 7) >> 3, c;
+ int w = font_glyph_pitch(vc->vc_font.width);
+ int c;
int y = real_y(par->p, vc->state.y);
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
@@ -261,14 +262,14 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
u32 vyres = GETVYRES(par->p, info);
u32 vxres = GETVXRES(par->p, info);
- if (!par->fontbuffer)
+ if (!par->rotated.buf)
return;
cursor.set = 0;
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
- src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
+ src = par->rotated.buf + ((c & charmask) * (w * vc->vc_font.height));
if (par->cursor_state.image.data != src ||
par->cursor_reset) {
@@ -325,50 +326,26 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
vc->vc_cursor_type != par->p->cursor_shape ||
par->cursor_state.mask == NULL ||
par->cursor_reset) {
- char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
- int cur_height, size, i = 0;
- u8 msk = 0xff;
+ unsigned char *tmp, *mask;
- if (!mask)
+ tmp = kmalloc_array(vc->vc_font.height, w, GFP_ATOMIC);
+ if (!tmp)
return;
+ fbcon_fill_cursor_mask(par, vc, tmp);
+
+ mask = kmalloc_array(vc->vc_font.height, w, GFP_ATOMIC);
+ if (!mask) {
+ kfree(tmp);
+ return;
+ }
+ font_glyph_rotate_180(tmp, vc->vc_font.width, vc->vc_font.height, mask);
+ kfree(tmp);
kfree(par->cursor_state.mask);
- par->cursor_state.mask = mask;
+ par->cursor_state.mask = (const char *)mask;
par->p->cursor_shape = vc->vc_cursor_type;
cursor.set |= FB_CUR_SETSHAPE;
-
- switch (CUR_SIZE(par->p->cursor_shape)) {
- case CUR_NONE:
- cur_height = 0;
- break;
- case CUR_UNDERLINE:
- cur_height = (vc->vc_font.height < 10) ? 1 : 2;
- break;
- case CUR_LOWER_THIRD:
- cur_height = vc->vc_font.height/3;
- break;
- case CUR_LOWER_HALF:
- cur_height = vc->vc_font.height >> 1;
- break;
- case CUR_TWO_THIRDS:
- cur_height = (vc->vc_font.height << 1)/3;
- break;
- case CUR_BLOCK:
- default:
- cur_height = vc->vc_font.height;
- break;
- }
-
- size = cur_height * w;
-
- while (size--)
- mask[i++] = msk;
-
- size = (vc->vc_font.height - cur_height) * w;
-
- while (size--)
- mask[i++] = ~msk;
}
par->cursor_state.enable = enable && !use_sw;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index cf199038f069..30f2b59c47bf 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -91,14 +91,14 @@ EXPORT_SYMBOL(fb_get_color_depth);
/*
* Data padding functions.
*/
-void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
+void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 s_pitch, u32 height)
{
__fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
}
EXPORT_SYMBOL(fb_pad_aligned_buffer);
-void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
- u32 shift_high, u32 shift_low, u32 mod)
+void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 idx, u32 height,
+ u32 shift_high, u32 shift_low, u32 mod)
{
u8 mask = (u8) (0xff << shift_high), tmp;
int i, j;
diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c
index ffe33a36b944..c9871281bc1d 100644
--- a/drivers/video/fbdev/goldfishfb.c
+++ b/drivers/video/fbdev/goldfishfb.c
@@ -174,7 +174,6 @@ static const struct fb_ops goldfish_fb_ops = {
static int goldfish_fb_probe(struct platform_device *pdev)
{
int ret;
- struct resource *r;
struct goldfish_fb *fb;
size_t framesize;
u32 width, height;
@@ -189,14 +188,9 @@ static int goldfish_fb_probe(struct platform_device *pdev)
init_waitqueue_head(&fb->wait);
platform_set_drvdata(pdev, fb);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- ret = -ENODEV;
- goto err_no_io_base;
- }
- fb->reg_base = ioremap(r->start, PAGE_SIZE);
- if (fb->reg_base == NULL) {
- ret = -ENOMEM;
+ fb->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(fb->reg_base)) {
+ ret = PTR_ERR(fb->reg_base);
goto err_no_io_base;
}
@@ -273,7 +267,6 @@ err_fb_set_var_failed:
fb->fb.fix.smem_start);
err_alloc_screen_base_failed:
err_no_irq:
- iounmap(fb->reg_base);
err_no_io_base:
kfree(fb);
err_fb_alloc_failed:
@@ -291,7 +284,6 @@ static void goldfish_fb_remove(struct platform_device *pdev)
dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base,
fb->fb.fix.smem_start);
- iounmap(fb->reg_base);
kfree(fb);
}
diff --git a/drivers/video/fbdev/macfb.c b/drivers/video/fbdev/macfb.c
index 887fffdccd24..ef3d2304e2f4 100644
--- a/drivers/video/fbdev/macfb.c
+++ b/drivers/video/fbdev/macfb.c
@@ -668,19 +668,19 @@ static int __init macfb_init(void)
switch(ndev->dr_hw) {
case NUBUS_DRHW_APPLE_MDC:
- strcpy(macfb_fix.id, "Mac Disp. Card");
+ strscpy(macfb_fix.id, "Mac Disp. Card");
macfb_setpalette = mdc_setpalette;
break;
case NUBUS_DRHW_APPLE_TFB:
- strcpy(macfb_fix.id, "Toby");
+ strscpy(macfb_fix.id, "Toby");
macfb_setpalette = toby_setpalette;
break;
case NUBUS_DRHW_APPLE_JET:
- strcpy(macfb_fix.id, "Jet");
+ strscpy(macfb_fix.id, "Jet");
macfb_setpalette = jet_setpalette;
break;
default:
- strcpy(macfb_fix.id, "Generic NuBus");
+ strscpy(macfb_fix.id, "Generic NuBus");
break;
}
}
@@ -707,7 +707,7 @@ static int __init macfb_init(void)
case MAC_MODEL_Q700:
case MAC_MODEL_Q900:
case MAC_MODEL_Q950:
- strcpy(macfb_fix.id, "DAFB");
+ strscpy(macfb_fix.id, "DAFB");
macfb_setpalette = dafb_setpalette;
dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
break;
@@ -716,7 +716,7 @@ static int __init macfb_init(void)
* LC II uses the V8 framebuffer
*/
case MAC_MODEL_LCII:
- strcpy(macfb_fix.id, "V8");
+ strscpy(macfb_fix.id, "V8");
macfb_setpalette = v8_brazil_setpalette;
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
@@ -729,7 +729,7 @@ static int __init macfb_init(void)
case MAC_MODEL_IIVI:
case MAC_MODEL_IIVX:
case MAC_MODEL_P600:
- strcpy(macfb_fix.id, "Brazil");
+ strscpy(macfb_fix.id, "Brazil");
macfb_setpalette = v8_brazil_setpalette;
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
@@ -745,7 +745,7 @@ static int __init macfb_init(void)
case MAC_MODEL_P520:
case MAC_MODEL_P550:
case MAC_MODEL_P460:
- strcpy(macfb_fix.id, "Sonora");
+ strscpy(macfb_fix.id, "Sonora");
macfb_setpalette = v8_brazil_setpalette;
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
@@ -757,7 +757,7 @@ static int __init macfb_init(void)
*/
case MAC_MODEL_IICI:
case MAC_MODEL_IISI:
- strcpy(macfb_fix.id, "RBV");
+ strscpy(macfb_fix.id, "RBV");
macfb_setpalette = rbv_setpalette;
rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
@@ -767,7 +767,7 @@ static int __init macfb_init(void)
*/
case MAC_MODEL_Q840:
case MAC_MODEL_C660:
- strcpy(macfb_fix.id, "Civic");
+ strscpy(macfb_fix.id, "Civic");
macfb_setpalette = civic_setpalette;
civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
break;
@@ -778,7 +778,7 @@ static int __init macfb_init(void)
* We think this may be like the LC II
*/
case MAC_MODEL_LC:
- strcpy(macfb_fix.id, "LC");
+ strscpy(macfb_fix.id, "LC");
if (vidtest) {
macfb_setpalette = v8_brazil_setpalette;
v8_brazil_cmap_regs =
@@ -790,7 +790,7 @@ static int __init macfb_init(void)
* We think this may be like the LC II
*/
case MAC_MODEL_CCL:
- strcpy(macfb_fix.id, "Color Classic");
+ strscpy(macfb_fix.id, "Color Classic");
if (vidtest) {
macfb_setpalette = v8_brazil_setpalette;
v8_brazil_cmap_regs =
@@ -802,7 +802,7 @@ static int __init macfb_init(void)
* And we *do* mean "weirdos"
*/
case MAC_MODEL_TV:
- strcpy(macfb_fix.id, "Mac TV");
+ strscpy(macfb_fix.id, "Mac TV");
break;
/*
@@ -810,7 +810,7 @@ static int __init macfb_init(void)
*/
case MAC_MODEL_SE30:
case MAC_MODEL_CLII:
- strcpy(macfb_fix.id, "Monochrome");
+ strscpy(macfb_fix.id, "Monochrome");
break;
/*
@@ -828,7 +828,7 @@ static int __init macfb_init(void)
case MAC_MODEL_PB140:
case MAC_MODEL_PB145:
case MAC_MODEL_PB170:
- strcpy(macfb_fix.id, "DDC");
+ strscpy(macfb_fix.id, "DDC");
break;
/*
@@ -840,7 +840,7 @@ static int __init macfb_init(void)
case MAC_MODEL_PB180:
case MAC_MODEL_PB210:
case MAC_MODEL_PB230:
- strcpy(macfb_fix.id, "GSC");
+ strscpy(macfb_fix.id, "GSC");
break;
/*
@@ -848,7 +848,7 @@ static int __init macfb_init(void)
*/
case MAC_MODEL_PB165C:
case MAC_MODEL_PB180C:
- strcpy(macfb_fix.id, "TIM");
+ strscpy(macfb_fix.id, "TIM");
break;
/*
@@ -860,13 +860,13 @@ static int __init macfb_init(void)
case MAC_MODEL_PB270C:
case MAC_MODEL_PB280:
case MAC_MODEL_PB280C:
- strcpy(macfb_fix.id, "CSC");
+ strscpy(macfb_fix.id, "CSC");
macfb_setpalette = csc_setpalette;
csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
break;
default:
- strcpy(macfb_fix.id, "Unknown");
+ strscpy(macfb_fix.id, "Unknown");
break;
}
diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c
index e2c1478aa47f..6a08f78cd1ac 100644
--- a/drivers/video/fbdev/matrox/g450_pll.c
+++ b/drivers/video/fbdev/matrox/g450_pll.c
@@ -409,7 +409,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
case M_VIDEO_PLL:
{
u_int8_t tmp;
- unsigned int mnp;
+ unsigned int mnp __maybe_unused;
unsigned long flags;
matroxfb_DAC_lock_irqsave(flags);
diff --git a/drivers/video/fbdev/omap/hwa742.c b/drivers/video/fbdev/omap/hwa742.c
index 64e76e1f5388..68a677f824e9 100644
--- a/drivers/video/fbdev/omap/hwa742.c
+++ b/drivers/video/fbdev/omap/hwa742.c
@@ -950,6 +950,8 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
omapfb_conf = dev_get_platdata(fbdev->dev);
hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck");
+ if (IS_ERR(hwa742.sys_ck))
+ return PTR_ERR(hwa742.sys_ck);
spin_lock_init(&hwa742.req_lock);
@@ -1028,6 +1030,7 @@ err3:
err2:
hwa742.int_ctrl->cleanup();
err1:
+ clk_put(hwa742.sys_ck);
return r;
}
@@ -1037,6 +1040,7 @@ static void hwa742_cleanup(void)
hwa742.extif->cleanup();
hwa742.int_ctrl->cleanup();
clk_disable_unprepare(hwa742.sys_ck);
+ clk_put(hwa742.sys_ck);
}
struct lcd_ctrl hwa742_ctrl = {
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
index a8b2930290e1..d70deb6a9150 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
@@ -1121,7 +1121,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return 0;
error:
- omapfb_put_mem_region(ofbi->region);
+ omapfb_put_mem_region(rg);
return r;
}
diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c
index 51ebe78359ec..4c4e53aaea3a 100644
--- a/drivers/video/fbdev/tdfxfb.c
+++ b/drivers/video/fbdev/tdfxfb.c
@@ -77,6 +77,7 @@
#include <asm/io.h>
#include <video/tdfx.h>
+#include <video/vga.h>
#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b)
@@ -496,6 +497,9 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
}
+ if (!var->pixclock)
+ return -EINVAL;
+
if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
DPRINTK("pixclock too high (%ldKHz)\n",
PICOS2KHZ(var->pixclock));
@@ -591,7 +595,7 @@ static int tdfxfb_set_par(struct fb_info *info)
vt = ve + (info->var.upper_margin << 1) - 1;
reg.screensize = info->var.xres | (info->var.yres << 13);
reg.vidcfg |= VIDCFG_HALF_MODE;
- reg.crt[0x09] = 0x80;
+ reg.crt[VGA_CRTC_MAX_SCAN] = 0x80;
} else {
vd = info->var.yres - 1;
vs = vd + info->var.lower_margin;
@@ -609,59 +613,59 @@ static int tdfxfb_set_par(struct fb_info *info)
info->var.xres < 480 ? 0x60 :
info->var.xres < 768 ? 0xe0 : 0x20);
- reg.gra[0x05] = 0x40;
- reg.gra[0x06] = 0x05;
- reg.gra[0x07] = 0x0f;
- reg.gra[0x08] = 0xff;
-
- reg.att[0x00] = 0x00;
- reg.att[0x01] = 0x01;
- reg.att[0x02] = 0x02;
- reg.att[0x03] = 0x03;
- reg.att[0x04] = 0x04;
- reg.att[0x05] = 0x05;
- reg.att[0x06] = 0x06;
- reg.att[0x07] = 0x07;
- reg.att[0x08] = 0x08;
- reg.att[0x09] = 0x09;
- reg.att[0x0a] = 0x0a;
- reg.att[0x0b] = 0x0b;
- reg.att[0x0c] = 0x0c;
- reg.att[0x0d] = 0x0d;
- reg.att[0x0e] = 0x0e;
- reg.att[0x0f] = 0x0f;
- reg.att[0x10] = 0x41;
- reg.att[0x12] = 0x0f;
-
- reg.seq[0x00] = 0x03;
- reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
- reg.seq[0x02] = 0x0f;
- reg.seq[0x03] = 0x00;
- reg.seq[0x04] = 0x0e;
-
- reg.crt[0x00] = ht - 4;
- reg.crt[0x01] = hd;
- reg.crt[0x02] = hbs;
- reg.crt[0x03] = 0x80 | (hbe & 0x1f);
- reg.crt[0x04] = hs;
- reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
- reg.crt[0x06] = vt;
- reg.crt[0x07] = ((vs & 0x200) >> 2) |
- ((vd & 0x200) >> 3) |
- ((vt & 0x200) >> 4) | 0x10 |
- ((vbs & 0x100) >> 5) |
- ((vs & 0x100) >> 6) |
- ((vd & 0x100) >> 7) |
- ((vt & 0x100) >> 8);
- reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4);
- reg.crt[0x10] = vs;
- reg.crt[0x11] = (ve & 0x0f) | 0x20;
- reg.crt[0x12] = vd;
- reg.crt[0x13] = wd;
- reg.crt[0x15] = vbs;
- reg.crt[0x16] = vbe + 1;
- reg.crt[0x17] = 0xc3;
- reg.crt[0x18] = 0xff;
+ reg.gra[VGA_GFX_MODE] = 0x40;
+ reg.gra[VGA_GFX_MISC] = 0x05;
+ reg.gra[VGA_GFX_COMPARE_MASK] = 0x0f;
+ reg.gra[VGA_GFX_BIT_MASK] = 0xff;
+
+ reg.att[VGA_ATC_PALETTE0] = 0x00;
+ reg.att[VGA_ATC_PALETTE1] = 0x01;
+ reg.att[VGA_ATC_PALETTE2] = 0x02;
+ reg.att[VGA_ATC_PALETTE3] = 0x03;
+ reg.att[VGA_ATC_PALETTE4] = 0x04;
+ reg.att[VGA_ATC_PALETTE5] = 0x05;
+ reg.att[VGA_ATC_PALETTE6] = 0x06;
+ reg.att[VGA_ATC_PALETTE7] = 0x07;
+ reg.att[VGA_ATC_PALETTE8] = 0x08;
+ reg.att[VGA_ATC_PALETTE9] = 0x09;
+ reg.att[VGA_ATC_PALETTEA] = 0x0a;
+ reg.att[VGA_ATC_PALETTEB] = 0x0b;
+ reg.att[VGA_ATC_PALETTEC] = 0x0c;
+ reg.att[VGA_ATC_PALETTED] = 0x0d;
+ reg.att[VGA_ATC_PALETTEE] = 0x0e;
+ reg.att[VGA_ATC_PALETTEF] = 0x0f;
+ reg.att[VGA_ATC_MODE] = 0x41;
+ reg.att[VGA_ATC_PLANE_ENABLE] = 0x0f;
+
+ reg.seq[VGA_SEQ_RESET] = 0x03;
+ reg.seq[VGA_SEQ_CLOCK_MODE] = 0x01; /* fixme: clkdiv2? */
+ reg.seq[VGA_SEQ_PLANE_WRITE] = 0x0f;
+ reg.seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
+ reg.seq[VGA_SEQ_MEMORY_MODE] = 0x0e;
+
+ reg.crt[VGA_CRTC_H_TOTAL] = ht - 4;
+ reg.crt[VGA_CRTC_H_DISP] = hd;
+ reg.crt[VGA_CRTC_H_BLANK_START] = hbs;
+ reg.crt[VGA_CRTC_H_BLANK_END] = 0x80 | (hbe & 0x1f);
+ reg.crt[VGA_CRTC_H_SYNC_START] = hs;
+ reg.crt[VGA_CRTC_H_SYNC_END] = ((hbe & 0x20) << 2) | (he & 0x1f);
+ reg.crt[VGA_CRTC_V_TOTAL] = vt;
+ reg.crt[VGA_CRTC_OVERFLOW] = ((vs & 0x200) >> 2) |
+ ((vd & 0x200) >> 3) |
+ ((vt & 0x200) >> 4) | 0x10 |
+ ((vbs & 0x100) >> 5) |
+ ((vs & 0x100) >> 6) |
+ ((vd & 0x100) >> 7) |
+ ((vt & 0x100) >> 8);
+ reg.crt[VGA_CRTC_MAX_SCAN] |= 0x40 | ((vbs & 0x200) >> 4);
+ reg.crt[VGA_CRTC_V_SYNC_START] = vs;
+ reg.crt[VGA_CRTC_V_SYNC_END] = (ve & 0x0f) | 0x20;
+ reg.crt[VGA_CRTC_V_DISP_END] = vd;
+ reg.crt[VGA_CRTC_OFFSET] = wd;
+ reg.crt[VGA_CRTC_V_BLANK_START] = vbs;
+ reg.crt[VGA_CRTC_V_BLANK_END] = vbe + 1;
+ reg.crt[VGA_CRTC_MODE] = 0xc3;
+ reg.crt[VGA_CRTC_LINE_COMPARE] = 0xff;
/* Banshee's nonvga stuff */
reg.ext[0x00] = (((ht & 0x100) >> 8) |
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index 3c6a9b5758d9..c341d76bc564 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -1018,6 +1018,9 @@ static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
struct fb_videomode mode;
struct dlfb_data *dlfb = info->par;
+ if (!var->pixclock)
+ return -EINVAL;
+
/* set device-specific elements of var unrelated to mode */
dlfb_var_color_format(var);
diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c
index 8673fced8749..3fa2304fbda7 100644
--- a/drivers/video/fbdev/via/lcd.c
+++ b/drivers/video/fbdev/via/lcd.c
@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile)
u16 start_pattern;
biosptr = ioremap(romaddr, 0x10000);
+ if (!biosptr)
+ return false;
+
start_pattern = readw(biosptr);
/* Compare pattern */
diff --git a/drivers/video/fbdev/wmt_ge_rops.c b/drivers/video/fbdev/wmt_ge_rops.c
index 2bd26bfb2b46..0cf78bcadfa6 100644
--- a/drivers/video/fbdev/wmt_ge_rops.c
+++ b/drivers/video/fbdev/wmt_ge_rops.c
@@ -148,25 +148,15 @@ EXPORT_SYMBOL_GPL(wmt_ge_sync);
static int wmt_ge_rops_probe(struct platform_device *pdev)
{
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no I/O memory resource defined\n");
- return -ENODEV;
- }
-
/* Only one ROP engine is presently supported. */
if (unlikely(regbase)) {
WARN_ON(1);
return -EBUSY;
}
- regbase = ioremap(res->start, resource_size(res));
- if (regbase == NULL) {
- dev_err(&pdev->dev, "failed to map I/O memory\n");
- return -EBUSY;
- }
+ regbase = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regbase))
+ return PTR_ERR(regbase);
writel(1, regbase + GE_ENABLE_OFF);
printk(KERN_INFO "Enabled support for WMT GE raster acceleration\n");
@@ -176,7 +166,7 @@ static int wmt_ge_rops_probe(struct platform_device *pdev)
static void wmt_ge_rops_remove(struct platform_device *pdev)
{
- iounmap(regbase);
+ regbase = NULL;
}
static const struct of_device_id wmt_dt_ids[] = {