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 ...
This commit is contained in:
commit
afac4c66d1
45 files changed
+1325
-787
No files matched your search
+23
@@ -10073,6 +10073,29 @@ S: Maintained
|
||||
W: https://floatingpoint.billm.au/
|
||||
F: arch/x86/math-emu/
|
||||
|
||||
FRAMEBUFFER CONSOLE
|
||||
M: Helge Deller <deller@gmx.de>
|
||||
M: Thomas Zimmermann <tzimmermann@suse.de>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: linux-fbdev@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
F: Documentation/fb/fbcon.rst
|
||||
F: drivers/video/fbdev/core/bitblit.c
|
||||
F: drivers/video/fbdev/core/fb_logo.c
|
||||
F: drivers/video/fbdev/core/fbcon.c
|
||||
F: drivers/video/fbdev/core/fbcon.h
|
||||
F: drivers/video/fbdev/core/fbcon_ccw.c
|
||||
F: drivers/video/fbdev/core/fbcon_cw.c
|
||||
F: drivers/video/fbdev/core/fbcon_rotate.c
|
||||
F: drivers/video/fbdev/core/fbcon_rotate.h
|
||||
F: drivers/video/fbdev/core/fbcon_ud.c
|
||||
F: drivers/video/fbdev/core/softcursor.c
|
||||
F: drivers/video/fbdev/core/tileblit.c
|
||||
F: include/linux/fbcon.h
|
||||
F: include/linux/font.h
|
||||
F: lib/fonts/
|
||||
|
||||
FRAMEBUFFER CORE
|
||||
M: Simona Vetter <simona@ffwll.ch>
|
||||
S: Odd Fixes
|
||||
|
||||
@@ -230,6 +230,40 @@ enum {
|
||||
blank_vesa_wait,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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/
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
font_data_get(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)++;
|
||||
|
||||
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;
|
||||
new_data = font_data_import(font, vpitch, crc32);
|
||||
if (IS_ERR(new_data))
|
||||
return PTR_ERR(new_data);
|
||||
|
||||
/* 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);
|
||||
|
||||
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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
unsigned char *buf;
|
||||
int ret;
|
||||
|
||||
if (vc->vc_font.data == par->fontdata &&
|
||||
par->p->con_rotate == par->cur_rotate)
|
||||
goto finished;
|
||||
if (par->p->fontdata == par->rotated.fontdata && par->rotate == par->rotated.buf_rotate)
|
||||
return 0;
|
||||
|
||||
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->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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+19
-19
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.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[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.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[0x00] = 0x03;
|
||||
reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
|
||||
reg.seq[0x02] = 0x0f;
|
||||
reg.seq[0x03] = 0x00;
|
||||
reg.seq[0x04] = 0x0e;
|
||||
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[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.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) |
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#ifndef _LINUX_CONSOLE_STRUCT_H
|
||||
#define _LINUX_CONSOLE_STRUCT_H
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/vt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct uni_pagedict;
|
||||
@@ -58,6 +58,33 @@ struct vc_state {
|
||||
bool reverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vc_font - Describes a font
|
||||
* @width: The width of a single glyph in bits
|
||||
* @height: The height of a single glyph in scanlines
|
||||
* @charcount: The number of glyphs in the font
|
||||
* @data: The raw font data
|
||||
*
|
||||
* Font data is organized as an array of glyphs. Each glyph is a bitmap with
|
||||
* set bits indicating the foreground color. Unset bits indicate background
|
||||
* color. The fields @width and @height store a single glyph's number of
|
||||
* horizontal bits and vertical scanlines. If width is not a multiple of 8,
|
||||
* there are trailing bits to fill up the byte. These bits should not be drawn.
|
||||
*
|
||||
* The field @data points to the first glyph's first byte. The value @charcount
|
||||
* gives the number of glyphs in the font. There are no empty scanlines between
|
||||
* two adjacent glyphs.
|
||||
*/
|
||||
struct vc_font {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int charcount;
|
||||
const unsigned char *data;
|
||||
};
|
||||
|
||||
unsigned int vc_font_pitch(const struct vc_font *font);
|
||||
unsigned int vc_font_size(const struct vc_font *font);
|
||||
|
||||
/*
|
||||
* Example: vc_data of a console that was scrolled 3 lines down.
|
||||
*
|
||||
@@ -120,9 +147,9 @@ struct vc_data {
|
||||
unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */
|
||||
unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */
|
||||
unsigned long vc_pos; /* Cursor address */
|
||||
/* fonts */
|
||||
/* fonts */
|
||||
unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
|
||||
struct console_font vc_font; /* Current VC font set */
|
||||
struct vc_font vc_font; /* Current VC font set */
|
||||
unsigned short vc_video_erase_char; /* Background erase character */
|
||||
/* VT terminal data */
|
||||
unsigned int vc_state; /* Escape sequence parser state */
|
||||
|
||||
+8
-11
@@ -217,14 +217,12 @@ struct fb_deferred_io {
|
||||
/* delay between mkwrite and deferred handler */
|
||||
unsigned long delay;
|
||||
bool sort_pagereflist; /* sort pagelist by offset */
|
||||
int open_count; /* number of opened files; protected by fb_info lock */
|
||||
struct mutex lock; /* mutex that protects the pageref list */
|
||||
struct list_head pagereflist; /* list of pagerefs for touched pages */
|
||||
struct address_space *mapping; /* page cache object for fb device */
|
||||
/* callback */
|
||||
struct page *(*get_page)(struct fb_info *info, unsigned long offset);
|
||||
void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
|
||||
};
|
||||
|
||||
struct fb_deferred_io_state;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -484,9 +482,8 @@ struct fb_info {
|
||||
|
||||
#ifdef CONFIG_FB_DEFERRED_IO
|
||||
struct delayed_work deferred_work;
|
||||
unsigned long npagerefs;
|
||||
struct fb_deferred_io_pageref *pagerefs;
|
||||
struct fb_deferred_io *fbdefio;
|
||||
struct fb_deferred_io_state *fbdefio_state;
|
||||
#endif
|
||||
|
||||
const struct fb_ops *fbops;
|
||||
@@ -605,9 +602,9 @@ extern int register_framebuffer(struct fb_info *fb_info);
|
||||
extern void unregister_framebuffer(struct fb_info *fb_info);
|
||||
extern int devm_register_framebuffer(struct device *dev, struct fb_info *fb_info);
|
||||
extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
|
||||
extern void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx,
|
||||
u32 height, u32 shift_high, u32 shift_low, u32 mod);
|
||||
extern void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height);
|
||||
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);
|
||||
void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 s_pitch, u32 height);
|
||||
extern void fb_set_suspend(struct fb_info *info, int state);
|
||||
extern int fb_get_color_depth(struct fb_var_screeninfo *var,
|
||||
struct fb_fix_screeninfo *fix);
|
||||
@@ -633,8 +630,8 @@ static inline struct device *dev_of_fbinfo(const struct fb_info *info)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch,
|
||||
u8 *src, u32 s_pitch, u32 height)
|
||||
static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, const u8 *src, u32 s_pitch,
|
||||
u32 height)
|
||||
{
|
||||
u32 i, j;
|
||||
|
||||
|
||||
+124
-42
@@ -11,47 +11,123 @@
|
||||
#ifndef _VIDEO_FONT_H
|
||||
#define _VIDEO_FONT_H
|
||||
|
||||
#include <linux/math.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct console_font;
|
||||
|
||||
/*
|
||||
* Glyphs
|
||||
*/
|
||||
|
||||
/**
|
||||
* font_glyph_pitch - Calculates the number of bytes per scanline
|
||||
* @width: The glyph width in bits per scanline
|
||||
*
|
||||
* A glyph's pitch is the number of bytes in a single scanline, rounded
|
||||
* up to the next full byte. The parameter @width receives the number
|
||||
* of visible bits per scanline. For example, if width is 14 bytes per
|
||||
* scanline, the pitch is 2 bytes per scanline. If width is 8 bits per
|
||||
* scanline, the pitch is 1 byte per scanline.
|
||||
*
|
||||
* Returns:
|
||||
* The number of bytes in a single scanline of the glyph
|
||||
*/
|
||||
static inline unsigned int font_glyph_pitch(unsigned int width)
|
||||
{
|
||||
return DIV_ROUND_UP(width, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* font_glyph_size - Calculates the number of bytes per glyph
|
||||
* @width: The glyph width in bits per scanline
|
||||
* @vpitch: The number of scanlines in the glyph
|
||||
*
|
||||
* The number of bytes in a glyph depends on the pitch and the number
|
||||
* of scanlines. font_glyph_size automatically calculates the pitch
|
||||
* from the given width. The parameter @vpitch gives the number of
|
||||
* scanlines, which is usually the glyph's height in scanlines. Fonts
|
||||
* coming from user space can sometimes have a different vertical pitch
|
||||
* with empty scanlines between two adjacent glyphs.
|
||||
*/
|
||||
static inline unsigned int font_glyph_size(unsigned int width, unsigned int vpitch)
|
||||
{
|
||||
return font_glyph_pitch(width) * vpitch;
|
||||
}
|
||||
|
||||
/*
|
||||
* font_data_t and helpers
|
||||
*/
|
||||
|
||||
/**
|
||||
* font_data_t - Raw font data
|
||||
*
|
||||
* Values of type font_data_t store a pointer to raw font data. The format
|
||||
* is monochrome. Each bit sets a pixel of a stored glyph. Font data does
|
||||
* not store geometry information for the individual glyphs. Users of the
|
||||
* font have to store glyph size, pitch and character count separately.
|
||||
*
|
||||
* Font data in font_data_t is not equivalent to raw u8. Each pointer stores
|
||||
* an additional hidden header before the font data. The layout is
|
||||
*
|
||||
* +------+-----------------------------+
|
||||
* | -16 | CRC32 Checksum (optional) |
|
||||
* | -12 | <Unused> |
|
||||
* | -8 | Number of data bytes |
|
||||
* | -4 | Reference count |
|
||||
* +------+-----------------------------+
|
||||
* | 0 | Data buffer |
|
||||
* | ... | |
|
||||
* +------+-----------------------------+
|
||||
*
|
||||
* Use helpers to access font_data_t. Use font_data_buf() to get the stored data.
|
||||
*/
|
||||
typedef const unsigned char font_data_t;
|
||||
|
||||
/**
|
||||
* font_data_buf() - Returns the font data as raw bytes
|
||||
* @fd: The font data
|
||||
*
|
||||
* Returns:
|
||||
* The raw font data. The provided buffer is read-only.
|
||||
*/
|
||||
static inline const unsigned char *font_data_buf(font_data_t *fd)
|
||||
{
|
||||
return (const unsigned char *)fd;
|
||||
}
|
||||
|
||||
font_data_t *font_data_import(const struct console_font *font, unsigned int vpitch,
|
||||
u32 (*calc_csum)(u32, const void *, size_t));
|
||||
void font_data_get(font_data_t *fd);
|
||||
bool font_data_put(font_data_t *fd);
|
||||
unsigned int font_data_size(font_data_t *fd);
|
||||
bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs);
|
||||
int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch);
|
||||
|
||||
/* font_rotate.c */
|
||||
void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height,
|
||||
unsigned char *out);
|
||||
void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height,
|
||||
unsigned char *out);
|
||||
void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height,
|
||||
unsigned char *out);
|
||||
unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
|
||||
unsigned int charcount, unsigned int steps,
|
||||
unsigned char *buf, size_t *bufsize);
|
||||
|
||||
/*
|
||||
* Font description
|
||||
*/
|
||||
|
||||
struct font_desc {
|
||||
int idx;
|
||||
const char *name;
|
||||
unsigned int width, height;
|
||||
unsigned int charcount;
|
||||
const void *data;
|
||||
font_data_t *data;
|
||||
int pref;
|
||||
};
|
||||
|
||||
#define VGA8x8_IDX 0
|
||||
#define VGA8x16_IDX 1
|
||||
#define PEARL8x8_IDX 2
|
||||
#define VGA6x11_IDX 3
|
||||
#define FONT7x14_IDX 4
|
||||
#define FONT10x18_IDX 5
|
||||
#define SUN8x16_IDX 6
|
||||
#define SUN12x22_IDX 7
|
||||
#define ACORN8x8_IDX 8
|
||||
#define MINI4x6_IDX 9
|
||||
#define FONT6x10_IDX 10
|
||||
#define TER16x32_IDX 11
|
||||
#define FONT6x8_IDX 12
|
||||
#define TER10x18_IDX 13
|
||||
|
||||
extern const struct font_desc font_vga_8x8,
|
||||
font_vga_8x16,
|
||||
font_pearl_8x8,
|
||||
font_vga_6x11,
|
||||
font_7x14,
|
||||
font_10x18,
|
||||
font_sun_8x16,
|
||||
font_sun_12x22,
|
||||
font_acorn_8x8,
|
||||
font_mini_4x6,
|
||||
font_6x10,
|
||||
font_ter_16x32,
|
||||
font_6x8,
|
||||
font_ter_10x18;
|
||||
|
||||
/* Find a font with a specific name */
|
||||
|
||||
extern const struct font_desc *find_font(const char *name);
|
||||
@@ -65,17 +141,23 @@ extern const struct font_desc *get_default_font(int xres, int yres,
|
||||
/* Max. length for the name of a predefined font */
|
||||
#define MAX_FONT_NAME 32
|
||||
|
||||
/* Extra word getters */
|
||||
#define REFCOUNT(fd) (((int *)(fd))[-1])
|
||||
#define FNTSIZE(fd) (((int *)(fd))[-2])
|
||||
#define FNTCHARCNT(fd) (((int *)(fd))[-3])
|
||||
#define FNTSUM(fd) (((int *)(fd))[-4])
|
||||
/*
|
||||
* Built-in fonts
|
||||
*/
|
||||
|
||||
#define FONT_EXTRA_WORDS 4
|
||||
|
||||
struct font_data {
|
||||
unsigned int extra[FONT_EXTRA_WORDS];
|
||||
const unsigned char data[];
|
||||
} __packed;
|
||||
extern const struct font_desc font_10x18;
|
||||
extern const struct font_desc font_6x10;
|
||||
extern const struct font_desc font_6x8;
|
||||
extern const struct font_desc font_7x14;
|
||||
extern const struct font_desc font_acorn_8x8;
|
||||
extern const struct font_desc font_mini_4x6;
|
||||
extern const struct font_desc font_pearl_8x8;
|
||||
extern const struct font_desc font_sun_12x22;
|
||||
extern const struct font_desc font_sun_8x16;
|
||||
extern const struct font_desc font_ter_10x18;
|
||||
extern const struct font_desc font_ter_16x32;
|
||||
extern const struct font_desc font_vga_6x11;
|
||||
extern const struct font_desc font_vga_8x16;
|
||||
extern const struct font_desc font_vga_8x8;
|
||||
|
||||
#endif /* _VIDEO_FONT_H */
|
||||
+18
-18
@@ -1,23 +1,23 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Font handling
|
||||
|
||||
font-objs := fonts.o
|
||||
font-y := fonts.o
|
||||
font-$(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION) += font_rotate.o
|
||||
|
||||
font-objs-$(CONFIG_FONT_SUN8x16) += font_sun8x16.o
|
||||
font-objs-$(CONFIG_FONT_SUN12x22) += font_sun12x22.o
|
||||
font-objs-$(CONFIG_FONT_8x8) += font_8x8.o
|
||||
font-objs-$(CONFIG_FONT_8x16) += font_8x16.o
|
||||
font-objs-$(CONFIG_FONT_6x11) += font_6x11.o
|
||||
font-objs-$(CONFIG_FONT_7x14) += font_7x14.o
|
||||
font-objs-$(CONFIG_FONT_10x18) += font_10x18.o
|
||||
font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
|
||||
font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
|
||||
font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
|
||||
font-objs-$(CONFIG_FONT_6x10) += font_6x10.o
|
||||
font-objs-$(CONFIG_FONT_TER10x18) += font_ter10x18.o
|
||||
font-objs-$(CONFIG_FONT_TER16x32) += font_ter16x32.o
|
||||
font-objs-$(CONFIG_FONT_6x8) += font_6x8.o
|
||||
# Built-in fonts; sorted by Family-Size in ascending order
|
||||
font-$(CONFIG_FONT_6x8) += font_6x8.o
|
||||
font-$(CONFIG_FONT_6x10) += font_6x10.o
|
||||
font-$(CONFIG_FONT_6x11) += font_6x11.o
|
||||
font-$(CONFIG_FONT_7x14) += font_7x14.o
|
||||
font-$(CONFIG_FONT_8x8) += font_8x8.o
|
||||
font-$(CONFIG_FONT_8x16) += font_8x16.o
|
||||
font-$(CONFIG_FONT_10x18) += font_10x18.o
|
||||
font-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
|
||||
font-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
|
||||
font-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
|
||||
font-$(CONFIG_FONT_SUN8x16) += font_sun8x16.o
|
||||
font-$(CONFIG_FONT_SUN12x22) += font_sun12x22.o
|
||||
font-$(CONFIG_FONT_TER10x18) += font_ter10x18.o
|
||||
font-$(CONFIG_FONT_TER16x32) += font_ter16x32.o
|
||||
|
||||
font-objs += $(font-objs-y)
|
||||
|
||||
obj-$(CONFIG_FONT_SUPPORT) += font.o
|
||||
obj-$(CONFIG_FONT_SUPPORT) += font.o
|
||||
@@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _LIB_FONTS_FONT_H
|
||||
#define _LIB_FONTS_FONT_H
|
||||
|
||||
#include <linux/font.h>
|
||||
|
||||
/*
|
||||
* Font data
|
||||
*/
|
||||
|
||||
#define FONT_EXTRA_WORDS 4
|
||||
|
||||
struct font_data {
|
||||
unsigned int extra[FONT_EXTRA_WORDS];
|
||||
unsigned char data[];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Built-in fonts
|
||||
*/
|
||||
|
||||
#define VGA8x8_IDX 0
|
||||
#define VGA8x16_IDX 1
|
||||
#define PEARL8x8_IDX 2
|
||||
#define VGA6x11_IDX 3
|
||||
#define FONT7x14_IDX 4
|
||||
#define FONT10x18_IDX 5
|
||||
#define SUN8x16_IDX 6
|
||||
#define SUN12x22_IDX 7
|
||||
#define ACORN8x8_IDX 8
|
||||
#define MINI4x6_IDX 9
|
||||
#define FONT6x10_IDX 10
|
||||
#define TER16x32_IDX 11
|
||||
#define FONT6x8_IDX 12
|
||||
#define TER10x18_IDX 13
|
||||
|
||||
#endif
|
||||
@@ -4,7 +4,7 @@
|
||||
* by Jurriaan Kalkman 06-2005 *
|
||||
********************************/
|
||||
|
||||
#include <linux/font.h>
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 9216
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/font.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 2560
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* */
|
||||
/**********************************************/
|
||||
|
||||
#include <linux/font.h>
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX (11*256)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/font.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 2048
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/* by Jurriaan Kalkman 05-2005 */
|
||||
/**************************************/
|
||||
|
||||
#include <linux/font.h>
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 3584
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
/* */
|
||||
/**********************************************/
|
||||
|
||||
#include <linux/font.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 4096
|
||||
|
||||
static const struct font_data fontdata_8x16 = {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* */
|
||||
/**********************************************/
|
||||
|
||||
#include <linux/font.h>
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 2048
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Acorn-like font definition, with PC graphics characters */
|
||||
|
||||
#include <linux/font.h>
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 2048
|
||||
|
||||
@@ -68,7 +68,7 @@ static const struct font_data acorndata_8x8 = {
|
||||
/* 3A */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, /* : */
|
||||
/* 3B */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, /* ; */
|
||||
/* 3C */ 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, /* < */
|
||||
/* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */
|
||||
/* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */
|
||||
/* 3E */ 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, /* > */
|
||||
/* 3F */ 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, /* ? */
|
||||
/* 40 */ 0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00, /* @ */
|
||||
|
||||
@@ -18,15 +18,15 @@
|
||||
s{((0x)?[0-9a-fA-F]+)(.*\[([\*\ ]{4})\])}{
|
||||
|
||||
($num,$pat,$bits) = ($1,$3,$4);
|
||||
|
||||
|
||||
$bits =~ s/([^\s0])|(.)/ defined($1) + 0 /ge;
|
||||
|
||||
|
||||
$num = ord(pack("B8", $bits));
|
||||
$num |= $num >> 4;
|
||||
$num = sprintf("0x%.2x", $num);
|
||||
|
||||
|
||||
#print "$num,$pat,$bits\n";
|
||||
|
||||
|
||||
$num . $pat;
|
||||
}ge;
|
||||
|
||||
@@ -39,7 +39,7 @@ __END__;
|
||||
MSBit to LSBit = left to right.
|
||||
*/
|
||||
|
||||
#include <linux/font.h>
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 1536
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/* */
|
||||
/**********************************************/
|
||||
|
||||
#include <linux/font.h>
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 2048
|
||||
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Font rotation
|
||||
*
|
||||
* Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
/* number of bits per line */
|
||||
static unsigned int font_glyph_bit_pitch(unsigned int width)
|
||||
{
|
||||
return round_up(width, 8);
|
||||
}
|
||||
|
||||
static unsigned int __font_glyph_pos(unsigned int x, unsigned int y, unsigned int bit_pitch,
|
||||
unsigned int *bit)
|
||||
{
|
||||
unsigned int off = y * bit_pitch + x;
|
||||
unsigned int bit_shift = off % 8;
|
||||
|
||||
*bit = 0x80 >> bit_shift; /* MSB has position 0, LSB has position 7 */
|
||||
|
||||
return off / 8;
|
||||
}
|
||||
|
||||
static bool font_glyph_test_bit(const unsigned char *glyph, unsigned int x, unsigned int y,
|
||||
unsigned int bit_pitch)
|
||||
{
|
||||
unsigned int bit;
|
||||
unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit);
|
||||
|
||||
return glyph[i] & bit;
|
||||
}
|
||||
|
||||
static void font_glyph_set_bit(unsigned char *glyph, unsigned int x, unsigned int y,
|
||||
unsigned int bit_pitch)
|
||||
{
|
||||
unsigned int bit;
|
||||
unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit);
|
||||
|
||||
glyph[i] |= bit;
|
||||
}
|
||||
|
||||
static void __font_glyph_rotate_90(const unsigned char *glyph,
|
||||
unsigned int width, unsigned int height,
|
||||
unsigned char *out)
|
||||
{
|
||||
unsigned int x, y;
|
||||
unsigned int shift = (8 - (height % 8)) & 7;
|
||||
unsigned int bit_pitch = font_glyph_bit_pitch(width);
|
||||
unsigned int out_bit_pitch = font_glyph_bit_pitch(height);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
if (font_glyph_test_bit(glyph, x, y, bit_pitch)) {
|
||||
font_glyph_set_bit(out, out_bit_pitch - 1 - y - shift, x,
|
||||
out_bit_pitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* font_glyph_rotate_90 - Rotate a glyph pattern by 90° in clockwise direction
|
||||
* @glyph: The glyph to rotate
|
||||
* @width: The glyph width in bits per scanline
|
||||
* @height: The number of scanlines in the glyph
|
||||
* @out: The rotated glyph bitmap
|
||||
*
|
||||
* The parameters @width and @height refer to the input glyph given in @glyph.
|
||||
* The caller has to provide the output buffer @out of sufficient size to hold
|
||||
* the rotated glyph. Rotating by 90° flips the width and height for the output
|
||||
* glyph. Depending on the glyph pitch, the size of the output glyph can be
|
||||
* different than the size of the input. Callers have to take this into account
|
||||
* when allocating the output memory.
|
||||
*/
|
||||
void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height,
|
||||
unsigned char *out)
|
||||
{
|
||||
memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
|
||||
|
||||
__font_glyph_rotate_90(glyph, width, height, out);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_glyph_rotate_90);
|
||||
|
||||
static void __font_glyph_rotate_180(const unsigned char *glyph,
|
||||
unsigned int width, unsigned int height,
|
||||
unsigned char *out)
|
||||
{
|
||||
unsigned int x, y;
|
||||
unsigned int shift = (8 - (width % 8)) & 7;
|
||||
unsigned int bit_pitch = font_glyph_bit_pitch(width);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
if (font_glyph_test_bit(glyph, x, y, bit_pitch)) {
|
||||
font_glyph_set_bit(out, width - (1 + x + shift), height - (1 + y),
|
||||
bit_pitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* font_glyph_rotate_180 - Rotate a glyph pattern by 180°
|
||||
* @glyph: The glyph to rotate
|
||||
* @width: The glyph width in bits per scanline
|
||||
* @height: The number of scanlines in the glyph
|
||||
* @out: The rotated glyph bitmap
|
||||
*
|
||||
* The parameters @width and @height refer to the input glyph given in @glyph.
|
||||
* The caller has to provide the output buffer @out of sufficient size to hold
|
||||
* the rotated glyph.
|
||||
*/
|
||||
void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height,
|
||||
unsigned char *out)
|
||||
{
|
||||
memset(out, 0, font_glyph_size(width, height));
|
||||
|
||||
__font_glyph_rotate_180(glyph, width, height, out);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_glyph_rotate_180);
|
||||
|
||||
static void __font_glyph_rotate_270(const unsigned char *glyph,
|
||||
unsigned int width, unsigned int height,
|
||||
unsigned char *out)
|
||||
{
|
||||
unsigned int x, y;
|
||||
unsigned int shift = (8 - (width % 8)) & 7;
|
||||
unsigned int bit_pitch = font_glyph_bit_pitch(width);
|
||||
unsigned int out_bit_pitch = font_glyph_bit_pitch(height);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
if (font_glyph_test_bit(glyph, x, y, bit_pitch))
|
||||
font_glyph_set_bit(out, y, bit_pitch - 1 - x - shift,
|
||||
out_bit_pitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* font_glyph_rotate_270 - Rotate a glyph pattern by 270° in clockwise direction
|
||||
* @glyph: The glyph to rotate
|
||||
* @width: The glyph width in bits per scanline
|
||||
* @height: The number of scanlines in the glyph
|
||||
* @out: The rotated glyph bitmap
|
||||
*
|
||||
* The parameters @width and @height refer to the input glyph given in @glyph.
|
||||
* The caller has to provide the output buffer @out of sufficient size to hold
|
||||
* the rotated glyph. Rotating by 270° flips the width and height for the output
|
||||
* glyph. Depending on the glyph pitch, the size of the output glyph can be
|
||||
* different than the size of the input. Callers have to take this into account
|
||||
* when allocating the output memory.
|
||||
*/
|
||||
void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height,
|
||||
unsigned char *out)
|
||||
{
|
||||
memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
|
||||
|
||||
__font_glyph_rotate_270(glyph, width, height, out);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
|
||||
|
||||
/**
|
||||
* font_data_rotate - Rotate font data by multiples of 90°
|
||||
* @fd: The font data to rotate
|
||||
* @width: The glyph width in bits per scanline
|
||||
* @height: The number of scanlines in the glyph
|
||||
* @charcount: The number of glyphs in the font
|
||||
* @steps: Number of rotation steps of 90°
|
||||
* @buf: Preallocated output buffer; can be NULL
|
||||
* @bufsize: The size of @buf in bytes; can be NULL
|
||||
*
|
||||
* The parameters @width and @height refer to the visible number of pixels
|
||||
* and scanlines in a single glyph. The number of glyphs is given in @charcount.
|
||||
* Rotation happens in steps of 90°. The @steps parameter can have any value,
|
||||
* but only 0 to 3 produce distinct results. With 4 or higher, a full rotation
|
||||
* has been performed. You can pass any value for @steps and the helper will
|
||||
* perform the appropriate rotation. Note that the returned buffer is not
|
||||
* compatible with font_data_t. It only contains glyph data in the same format
|
||||
* as returned by font_data_buf(). Callers are responsible to free the returned
|
||||
* buffer with kfree(). Font rotation typically happens when displays get
|
||||
* re-oriented. To avoid unnecessary re-allocation of the memory buffer, the
|
||||
* caller can pass in an earlier result buffer in @buf for reuse. The old and
|
||||
* new buffer sizes are given and retrieved by the caller in @bufsize. The
|
||||
* allocation semantics are compatible with krealloc().
|
||||
*
|
||||
* Returns:
|
||||
* A buffer with rotated glyphs on success, or an error pointer otherwise
|
||||
*/
|
||||
unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
|
||||
unsigned int charcount, unsigned int steps,
|
||||
unsigned char *buf, size_t *bufsize)
|
||||
{
|
||||
const unsigned char *src = font_data_buf(fd);
|
||||
unsigned int s_cellsize = font_glyph_size(width, height);
|
||||
unsigned int d_cellsize, i;
|
||||
unsigned char *dst;
|
||||
size_t size;
|
||||
|
||||
steps %= 4;
|
||||
|
||||
switch (steps) {
|
||||
case 0:
|
||||
case 2:
|
||||
d_cellsize = s_cellsize;
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
d_cellsize = font_glyph_size(height, width); /* flip width/height */
|
||||
break;
|
||||
}
|
||||
|
||||
if (check_mul_overflow(charcount, d_cellsize, &size))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!buf || !bufsize || size > *bufsize) {
|
||||
dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL);
|
||||
if (!dst)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
kfree(buf);
|
||||
buf = dst;
|
||||
if (bufsize)
|
||||
*bufsize = size;
|
||||
} else {
|
||||
dst = buf;
|
||||
}
|
||||
|
||||
switch (steps) {
|
||||
case 0:
|
||||
memcpy(dst, src, size);
|
||||
break;
|
||||
case 1:
|
||||
memset(dst, 0, size);
|
||||
for (i = 0; i < charcount; ++i) {
|
||||
__font_glyph_rotate_90(src, width, height, dst);
|
||||
src += s_cellsize;
|
||||
dst += d_cellsize;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
memset(dst, 0, size);
|
||||
for (i = 0; i < charcount; ++i) {
|
||||
__font_glyph_rotate_180(src, width, height, dst);
|
||||
src += s_cellsize;
|
||||
dst += d_cellsize;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
memset(dst, 0, size);
|
||||
for (i = 0; i < charcount; ++i) {
|
||||
__font_glyph_rotate_270(src, width, height, dst);
|
||||
src += s_cellsize;
|
||||
dst += d_cellsize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_data_rotate);
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/font.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 11264
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/font.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 4096
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/font.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 9216
|
||||
|
||||
static const struct font_data fontdata_ter10x18 = {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/font.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define FONTDATAMAX 16384
|
||||
|
||||
static const struct font_data fontdata_ter16x32 = {
|
||||
|
||||
+230
-2
@@ -12,13 +12,241 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#if defined(__mc68000__)
|
||||
#include <asm/setup.h>
|
||||
#endif
|
||||
#include <linux/font.h>
|
||||
|
||||
#include "font.h"
|
||||
|
||||
#define console_font_pitch(font) font_glyph_pitch((font)->width)
|
||||
|
||||
/*
|
||||
* Helpers for font_data_t
|
||||
*/
|
||||
|
||||
/* Extra word getters */
|
||||
#define REFCOUNT(fd) (((int *)(fd))[-1])
|
||||
#define FNTSIZE(fd) (((int *)(fd))[-2])
|
||||
#define FNTSUM(fd) (((int *)(fd))[-4])
|
||||
|
||||
static struct font_data *to_font_data_struct(font_data_t *fd)
|
||||
{
|
||||
return container_of(fd, struct font_data, data[0]);
|
||||
}
|
||||
|
||||
static bool font_data_is_internal(font_data_t *fd)
|
||||
{
|
||||
return !REFCOUNT(fd); /* internal fonts have no reference counting */
|
||||
}
|
||||
|
||||
static void font_data_free(font_data_t *fd)
|
||||
{
|
||||
kfree(to_font_data_struct(fd));
|
||||
}
|
||||
|
||||
/**
|
||||
* font_data_import - Allocates and initializes font data from user space
|
||||
* @font: A font from user space
|
||||
* @vpitch: The size of a single glyph in @font in bytes
|
||||
* @calc_csum: An optional helper to calculate a chechsum
|
||||
*
|
||||
* Font data from user space must be translated to the kernel's format. The
|
||||
* font's glyph geometry and data is provided in @font. The parameter @vpitch
|
||||
* gives the number of bytes per glyph, including trailing bytes.
|
||||
*
|
||||
* The parameter @calc_csum is optional. Fbcon passes crc32() to calculate the
|
||||
* font data's checksum.
|
||||
*
|
||||
* Returns:
|
||||
* Newly initialized font data on success, or a pointer-encoded errno value otherwise.
|
||||
*/
|
||||
font_data_t *font_data_import(const struct console_font *font, unsigned int vpitch,
|
||||
u32 (*calc_csum)(u32, const void *, size_t))
|
||||
{
|
||||
unsigned int pitch = console_font_pitch(font);
|
||||
unsigned int h = font->height;
|
||||
unsigned int charcount = font->charcount;
|
||||
const unsigned char *data = font->data;
|
||||
u32 csum = 0;
|
||||
struct font_data *font_data;
|
||||
int size, alloc_size;
|
||||
unsigned int i;
|
||||
font_data_t *fd;
|
||||
|
||||
/* Check for integer overflow in font-size calculation */
|
||||
if (check_mul_overflow(h, pitch, &size) ||
|
||||
check_mul_overflow(size, charcount, &size))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Check for overflow in allocation size calculation */
|
||||
if (check_add_overflow(sizeof(*font_data), size, &alloc_size))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
font_data = kmalloc(alloc_size, GFP_USER);
|
||||
if (!font_data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
memset(font_data->extra, 0, sizeof(font_data->extra));
|
||||
|
||||
for (i = 0; i < charcount; ++i)
|
||||
memcpy(font_data->data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
|
||||
|
||||
if (calc_csum)
|
||||
csum = calc_csum(0, font_data->data, size);
|
||||
|
||||
fd = font_data->data;
|
||||
REFCOUNT(fd) = 1; /* start with reference acquired */
|
||||
FNTSIZE(fd) = size;
|
||||
FNTSUM(fd) = csum;
|
||||
|
||||
return fd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_data_import);
|
||||
|
||||
/**
|
||||
* font_data_get - Acquires a reference on font data
|
||||
* @fd: Font data
|
||||
*
|
||||
* Font data from user space is reference counted. The helper
|
||||
* font_data_get() increases the reference counter by one. Invoke
|
||||
* font_data_put() to release the reference.
|
||||
*
|
||||
* Internal font data is located in read-only memory. In this case
|
||||
* the helper returns success without modifying the counter field.
|
||||
* It is still required to call font_data_put() on internal font data.
|
||||
*/
|
||||
void font_data_get(font_data_t *fd)
|
||||
{
|
||||
if (font_data_is_internal(fd))
|
||||
return; /* never ref static data */
|
||||
|
||||
if (WARN_ON(!REFCOUNT(fd)))
|
||||
return; /* should never be 0 */
|
||||
++REFCOUNT(fd);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_data_get);
|
||||
|
||||
/**
|
||||
* font_data_put - Release a reference on font data
|
||||
* @fd: Font data
|
||||
*
|
||||
* Font data from user space is reference counted. The helper
|
||||
* font_data_put() decreases the reference counter by one. If this was
|
||||
* the final reference, it frees the allocated memory.
|
||||
*
|
||||
* Internal font data is located in read-only memory. In this case
|
||||
* the helper returns success without modifying the counter field.
|
||||
*
|
||||
* Returns:
|
||||
* True if the font data's memory buffer has been freed, false otherwise.
|
||||
*/
|
||||
bool font_data_put(font_data_t *fd)
|
||||
{
|
||||
unsigned int count;
|
||||
|
||||
if (font_data_is_internal(fd))
|
||||
return false; /* never unref static data */
|
||||
|
||||
if (WARN_ON(!REFCOUNT(fd)))
|
||||
return false; /* should never be 0 */
|
||||
|
||||
count = --REFCOUNT(fd);
|
||||
if (!count)
|
||||
font_data_free(fd);
|
||||
|
||||
return !count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_data_put);
|
||||
|
||||
/**
|
||||
* font_data_size - Return size of the font data in bytes
|
||||
* @fd: Font data
|
||||
*
|
||||
* Returns:
|
||||
* The number of bytes in the given font data.
|
||||
*/
|
||||
unsigned int font_data_size(font_data_t *fd)
|
||||
{
|
||||
return FNTSIZE(fd);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_data_size);
|
||||
|
||||
/**
|
||||
* font_data_is_equal - Compares font data for equality
|
||||
* @lhs: Left-hand side font data
|
||||
* @rhs: Right-hand-size font data
|
||||
*
|
||||
* Font data is equal if is constain the same sequence of values. The
|
||||
* helper also use the checksum, if both arguments contain it. Font data
|
||||
* coming from different origins, internal or from user space, is never
|
||||
* equal. Allowing this would break reference counting.
|
||||
*
|
||||
* Returns:
|
||||
* True if the given font data is equal, false otherwise.
|
||||
*/
|
||||
bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs)
|
||||
{
|
||||
if (font_data_is_internal(lhs) != font_data_is_internal(rhs))
|
||||
return false;
|
||||
if (font_data_size(lhs) != font_data_size(rhs))
|
||||
return false;
|
||||
if (FNTSUM(lhs) && FNTSUM(rhs) && FNTSUM(lhs) != FNTSUM(rhs))
|
||||
return false;
|
||||
|
||||
return !memcmp(lhs, rhs, FNTSIZE(lhs));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_data_is_equal);
|
||||
|
||||
/**
|
||||
* font_data_export - Stores font data for user space
|
||||
* @fd: Font data
|
||||
* @font: A font for user space
|
||||
* @vpitch: The size of a single glyph in @font in bytes
|
||||
*
|
||||
* Store the font data given in @fd to the font in @font. Values and
|
||||
* pointers in @font are pre-initialized. This helper mostly checks some
|
||||
* corner cases and translates glyph sizes according to the value given
|
||||
* @vpitch.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, or a negative errno code otherwise.
|
||||
*/
|
||||
int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch)
|
||||
{
|
||||
const unsigned char *font_data = font_data_buf(fd);
|
||||
unsigned char *data = font->data;
|
||||
unsigned int pitch = console_font_pitch(font);
|
||||
unsigned int glyphsize, i;
|
||||
|
||||
if (!font->width || !font->height || !font->charcount || !font->data)
|
||||
return 0;
|
||||
|
||||
glyphsize = font->height * pitch;
|
||||
|
||||
if (font->charcount * glyphsize > font_data_size(fd))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < font->charcount; i++) {
|
||||
memcpy(data, font_data, glyphsize);
|
||||
memset(data + glyphsize, 0, pitch * vpitch - glyphsize);
|
||||
data += pitch * vpitch;
|
||||
font_data += glyphsize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(font_data_export);
|
||||
|
||||
/*
|
||||
* Font lookup
|
||||
*/
|
||||
|
||||
static const struct font_desc *fonts[] = {
|
||||
#ifdef CONFIG_FONT_8x8
|
||||
|
||||
Reference in new issue
Block a user