Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
d77e03bd
Commit
d77e03bd
authored
Jan 01, 2003
by
Richard Henderson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[TGAFB] Implement the fb_copyarea hook.
parent
b4d7b6ea
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
452 additions
and
7 deletions
+452
-7
drivers/video/tgafb.c
drivers/video/tgafb.c
+452
-7
No files found.
drivers/video/tgafb.c
View file @
d77e03bd
...
...
@@ -42,6 +42,7 @@ static void tgafb_init_fix(struct fb_info *);
static
void
tgafb_imageblit
(
struct
fb_info
*
,
struct
fb_image
*
);
static
void
tgafb_fillrect
(
struct
fb_info
*
,
struct
fb_fillrect
*
);
static
void
tgafb_copyarea
(
struct
fb_info
*
,
struct
fb_copyarea
*
);
static
int
tgafb_pci_register
(
struct
pci_dev
*
,
const
struct
pci_device_id
*
);
#ifdef MODULE
...
...
@@ -62,7 +63,7 @@ static struct fb_ops tgafb_ops = {
.
fb_setcolreg
=
tgafb_setcolreg
,
.
fb_blank
=
tgafb_blank
,
.
fb_fillrect
=
tgafb_fillrect
,
.
fb_copyarea
=
c
fb_copyarea
,
.
fb_copyarea
=
tga
fb_copyarea
,
.
fb_imageblit
=
tgafb_imageblit
,
.
fb_cursor
=
soft_cursor
,
};
...
...
@@ -96,10 +97,10 @@ tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
if
(
par
->
tga_type
==
TGA_TYPE_8PLANE
)
{
if
(
var
->
bits_per_pixel
>
8
)
if
(
var
->
bits_per_pixel
!=
8
)
return
-
EINVAL
;
}
else
{
if
(
var
->
bits_per_pixel
>
32
)
if
(
var
->
bits_per_pixel
!=
32
)
return
-
EINVAL
;
}
...
...
@@ -112,6 +113,11 @@ tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
if
((
var
->
vmode
&
FB_VMODE_MASK
)
!=
FB_VMODE_NONINTERLACED
)
return
-
EINVAL
;
/* Some of the acceleration routines assume the line width is
a multiple of 64 bytes. */
if
(
var
->
xres
*
(
par
->
tga_type
==
TGA_TYPE_8PLANE
?
1
:
4
)
%
64
)
return
-
EINVAL
;
return
0
;
}
...
...
@@ -505,6 +511,14 @@ tgafb_blank(int blank, struct fb_info *info)
* Acceleration.
*/
/**
* tgafb_imageblit - REQUIRED function. Can use generic routines if
* non acclerated hardware and packed pixel based.
* Copies a image from system memory to the screen.
*
* @info: frame buffer structure that represents a single frame buffer
* @image: structure defining the image.
*/
static
void
tgafb_imageblit
(
struct
fb_info
*
info
,
struct
fb_image
*
image
)
{
...
...
@@ -578,7 +592,7 @@ tgafb_imageblit(struct fb_info *info, struct fb_image *image)
regs_base
=
par
->
tga_regs_base
;
fb_base
=
par
->
tga_fb_base
;
is8bpp
=
par
->
tga_type
==
TGA_TYPE_8PLANE
;
is8bpp
=
info
->
var
.
bits_per_pixel
==
8
;
/* Expand the color values to fill 32-bits. */
/* ??? Would be nice to notice colour changes elsewhere, so
...
...
@@ -756,11 +770,19 @@ tgafb_imageblit(struct fb_info *info, struct fb_image *image)
regs_base
+
TGA_MODE_REG
);
}
/**
* tgafb_fillrect - REQUIRED function. Can use generic routines if
* non acclerated hardware and packed pixel based.
* Draws a rectangle on the screen.
*
* @info: frame buffer structure that represents a single frame buffer
* @rect: structure defining the rectagle and operation.
*/
static
void
tgafb_fillrect
(
struct
fb_info
*
info
,
struct
fb_fillrect
*
rect
)
{
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
int
is8bpp
=
par
->
tga_type
==
TGA_TYPE_8PLANE
;
int
is8bpp
=
info
->
var
.
bits_per_pixel
==
8
;
u32
dx
,
dy
,
width
,
height
,
vxres
,
vyres
,
color
;
unsigned
long
pos
,
align
,
line_length
,
i
,
j
;
void
*
regs_base
,
*
fb_base
;
...
...
@@ -790,7 +812,6 @@ tgafb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
tell, this mode is not actually used in the kernel.
Thus I am ignoring it for now. */
if
(
rect
->
rop
!=
ROP_COPY
)
{
printk
(
KERN_DEBUG
"tgafb: fillrect saw rop != ROP_COPY
\n
"
);
cfb_fillrect
(
info
,
rect
);
return
;
}
...
...
@@ -872,6 +893,430 @@ tgafb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
regs_base
+
TGA_MODE_REG
);
}
/**
* tgafb_copyarea - REQUIRED function. Can use generic routines if
* non acclerated hardware and packed pixel based.
* Copies on area of the screen to another area.
*
* @info: frame buffer structure that represents a single frame buffer
* @area: structure defining the source and destination.
*/
/* Handle the special case of copying entire lines, e.g. during scrolling.
We can avoid a lot of needless computation in this case. In the 8bpp
case we need to use the COPY64 registers instead of mask writes into
the frame buffer to achieve maximum performance. */
static
inline
void
copyarea_line_8bpp
(
struct
fb_info
*
info
,
u32
dy
,
u32
sy
,
u32
height
,
u32
width
)
{
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
void
*
tga_regs
=
par
->
tga_regs_base
;
unsigned
long
dpos
,
spos
,
i
,
n64
;
/* Set up the MODE and PIXELSHIFT registers. */
__raw_writel
(
TGA_MODE_SBM_8BPP
|
TGA_MODE_COPY
,
tga_regs
+
TGA_MODE_REG
);
__raw_writel
(
0
,
tga_regs
+
TGA_PIXELSHIFT_REG
);
wmb
();
n64
=
(
height
*
width
)
/
64
;
if
(
dy
<
sy
)
{
spos
=
(
sy
+
height
)
*
width
;
dpos
=
(
dy
+
height
)
*
width
;
for
(
i
=
0
;
i
<
n64
;
++
i
)
{
spos
-=
64
;
dpos
-=
64
;
__raw_writel
(
spos
,
tga_regs
+
TGA_COPY64_SRC
);
wmb
();
__raw_writel
(
dpos
,
tga_regs
+
TGA_COPY64_DST
);
wmb
();
}
}
else
{
spos
=
sy
*
width
;
dpos
=
dy
*
width
;
for
(
i
=
0
;
i
<
n64
;
++
i
)
{
__raw_writel
(
spos
,
tga_regs
+
TGA_COPY64_SRC
);
wmb
();
__raw_writel
(
dpos
,
tga_regs
+
TGA_COPY64_DST
);
wmb
();
spos
+=
64
;
dpos
+=
64
;
}
}
/* Reset the MODE register to normal. */
__raw_writel
(
TGA_MODE_SBM_8BPP
|
TGA_MODE_SIMPLE
,
tga_regs
+
TGA_MODE_REG
);
}
static
inline
void
copyarea_line_32bpp
(
struct
fb_info
*
info
,
u32
dy
,
u32
sy
,
u32
height
,
u32
width
)
{
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
void
*
tga_regs
=
par
->
tga_regs_base
;
void
*
tga_fb
=
par
->
tga_fb_base
;
void
*
src
,
*
dst
;
unsigned
long
i
,
n16
;
/* Set up the MODE and PIXELSHIFT registers. */
__raw_writel
(
TGA_MODE_SBM_24BPP
|
TGA_MODE_COPY
,
tga_regs
+
TGA_MODE_REG
);
__raw_writel
(
0
,
tga_regs
+
TGA_PIXELSHIFT_REG
);
wmb
();
n16
=
(
height
*
width
)
/
16
;
if
(
dy
<
sy
)
{
src
=
tga_fb
+
(
sy
+
height
)
*
width
*
4
;
dst
=
tga_fb
+
(
dy
+
height
)
*
width
*
4
;
for
(
i
=
0
;
i
<
n16
;
++
i
)
{
src
-=
64
;
dst
-=
64
;
__raw_writel
(
0xffff
,
src
);
wmb
();
__raw_writel
(
0xffff
,
dst
);
wmb
();
}
}
else
{
src
=
tga_fb
+
sy
*
width
*
4
;
dst
=
tga_fb
+
dy
*
width
*
4
;
for
(
i
=
0
;
i
<
n16
;
++
i
)
{
__raw_writel
(
0xffff
,
src
);
wmb
();
__raw_writel
(
0xffff
,
dst
);
wmb
();
src
+=
64
;
dst
+=
64
;
}
}
/* Reset the MODE register to normal. */
__raw_writel
(
TGA_MODE_SBM_24BPP
|
TGA_MODE_SIMPLE
,
tga_regs
+
TGA_MODE_REG
);
}
/* The general case of forward copy in 8bpp mode. */
static
inline
void
copyarea_foreward_8bpp
(
struct
fb_info
*
info
,
u32
dx
,
u32
dy
,
u32
sx
,
u32
sy
,
u32
height
,
u32
width
,
u32
line_length
)
{
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
unsigned
long
i
,
copied
,
left
;
unsigned
long
dpos
,
spos
,
dalign
,
salign
,
yincr
;
u32
smask_first
,
dmask_first
,
dmask_last
;
int
pixel_shift
,
need_prime
,
need_second
;
unsigned
long
n64
,
n32
,
xincr_first
;
void
*
tga_regs
,
*
tga_fb
;
yincr
=
line_length
;
if
(
dy
>
sy
)
{
dy
+=
height
-
1
;
sy
+=
height
-
1
;
yincr
=
-
yincr
;
}
/* Compute the offsets and alignments in the frame buffer.
More than anything else, these control how we do copies. */
dpos
=
dy
*
line_length
+
dx
;
spos
=
sy
*
line_length
+
sx
;
dalign
=
dpos
&
7
;
salign
=
spos
&
7
;
dpos
&=
-
8
;
spos
&=
-
8
;
/* Compute the value for the PIXELSHIFT register. This controls
both non-co-aligned source and destination and copy direction. */
if
(
dalign
>=
salign
)
pixel_shift
=
dalign
-
salign
;
else
pixel_shift
=
8
-
(
salign
-
dalign
);
/* Figure out if we need an additional priming step for the
residue register. */
need_prime
=
(
salign
>
dalign
);
if
(
need_prime
)
dpos
-=
8
;
/* Begin by copying the leading unaligned destination. Copy enough
to make the next destination address 32-byte aligned. */
copied
=
32
-
(
dalign
+
(
dpos
&
31
));
if
(
copied
==
32
)
copied
=
0
;
xincr_first
=
(
copied
+
7
)
&
-
8
;
smask_first
=
dmask_first
=
(
1ul
<<
copied
)
-
1
;
smask_first
<<=
salign
;
dmask_first
<<=
dalign
+
need_prime
*
8
;
if
(
need_prime
&&
copied
>
24
)
copied
-=
8
;
left
=
width
-
copied
;
/* Care for small copies. */
if
(
copied
>
width
)
{
u32
t
;
t
=
(
1ul
<<
width
)
-
1
;
t
<<=
dalign
+
need_prime
*
8
;
dmask_first
&=
t
;
left
=
0
;
}
/* Attempt to use 64-byte copies. This is only possible if the
source and destination are co-aligned at 64 bytes. */
n64
=
need_second
=
0
;
if
((
dpos
&
63
)
==
(
spos
&
63
)
&&
(
height
==
1
||
line_length
%
64
==
0
))
{
/* We may need a 32-byte copy to ensure 64 byte alignment. */
need_second
=
(
dpos
+
xincr_first
)
&
63
;
if
((
need_second
&
32
)
!=
need_second
)
printk
(
KERN_ERR
"tgafb: need_second wrong
\n
"
);
if
(
left
>=
need_second
+
64
)
{
left
-=
need_second
;
n64
=
left
/
64
;
left
%=
64
;
}
else
need_second
=
0
;
}
/* Copy trailing full 32-byte sections. This will be the main
loop if the 64 byte loop can't be used. */
n32
=
left
/
32
;
left
%=
32
;
/* Copy the trailing unaligned destination. */
dmask_last
=
(
1ul
<<
left
)
-
1
;
tga_regs
=
par
->
tga_regs_base
;
tga_fb
=
par
->
tga_fb_base
;
/* Set up the MODE and PIXELSHIFT registers. */
__raw_writel
(
TGA_MODE_SBM_8BPP
|
TGA_MODE_COPY
,
tga_regs
+
TGA_MODE_REG
);
__raw_writel
(
pixel_shift
,
tga_regs
+
TGA_PIXELSHIFT_REG
);
wmb
();
for
(
i
=
0
;
i
<
height
;
++
i
)
{
unsigned
long
j
;
void
*
sfb
,
*
dfb
;
sfb
=
tga_fb
+
spos
;
dfb
=
tga_fb
+
dpos
;
if
(
dmask_first
)
{
__raw_writel
(
smask_first
,
sfb
);
wmb
();
__raw_writel
(
dmask_first
,
dfb
);
wmb
();
sfb
+=
xincr_first
;
dfb
+=
xincr_first
;
}
if
(
need_second
)
{
__raw_writel
(
0xffffffff
,
sfb
);
wmb
();
__raw_writel
(
0xffffffff
,
dfb
);
wmb
();
sfb
+=
32
;
dfb
+=
32
;
}
if
(
n64
&&
(((
long
)
sfb
|
(
long
)
dfb
)
&
63
))
printk
(
KERN_ERR
"tgafb: misaligned copy64 (s:%p, d:%p)
\n
"
,
sfb
,
dfb
);
for
(
j
=
0
;
j
<
n64
;
++
j
)
{
__raw_writel
(
sfb
-
tga_fb
,
tga_regs
+
TGA_COPY64_SRC
);
wmb
();
__raw_writel
(
dfb
-
tga_fb
,
tga_regs
+
TGA_COPY64_DST
);
wmb
();
sfb
+=
64
;
dfb
+=
64
;
}
for
(
j
=
0
;
j
<
n32
;
++
j
)
{
__raw_writel
(
0xffffffff
,
sfb
);
wmb
();
__raw_writel
(
0xffffffff
,
dfb
);
wmb
();
sfb
+=
32
;
dfb
+=
32
;
}
if
(
dmask_last
)
{
__raw_writel
(
0xffffffff
,
sfb
);
wmb
();
__raw_writel
(
dmask_last
,
dfb
);
wmb
();
}
spos
+=
yincr
;
dpos
+=
yincr
;
}
/* Reset the MODE register to normal. */
__raw_writel
(
TGA_MODE_SBM_8BPP
|
TGA_MODE_SIMPLE
,
tga_regs
+
TGA_MODE_REG
);
}
/* The (almost) general case of backward copy in 8bpp mode. */
static
inline
void
copyarea_backward_8bpp
(
struct
fb_info
*
info
,
u32
dx
,
u32
dy
,
u32
sx
,
u32
sy
,
u32
height
,
u32
width
,
u32
line_length
,
struct
fb_copyarea
*
area
)
{
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
unsigned
long
i
,
left
,
yincr
;
unsigned
long
depos
,
sepos
,
dealign
,
sealign
;
u32
mask_first
,
mask_last
;
unsigned
long
n32
;
void
*
tga_regs
,
*
tga_fb
;
yincr
=
line_length
;
if
(
dy
>
sy
)
{
dy
+=
height
-
1
;
sy
+=
height
-
1
;
yincr
=
-
yincr
;
}
/* Compute the offsets and alignments in the frame buffer.
More than anything else, these control how we do copies. */
depos
=
dy
*
line_length
+
dx
+
width
;
sepos
=
sy
*
line_length
+
sx
+
width
;
dealign
=
depos
&
7
;
sealign
=
sepos
&
7
;
/* ??? The documentation appears to be incorrect (or very
misleading) wrt how pixel shifting works in backward copy
mode, i.e. when PIXELSHIFT is negative. I give up for now.
Do handle the common case of co-aligned backward copies,
but frob everything else back on generic code. */
if
(
dealign
!=
sealign
)
{
cfb_copyarea
(
info
,
area
);
return
;
}
/* We begin the copy with the trailing pixels of the
unaligned destination. */
mask_first
=
(
1ul
<<
dealign
)
-
1
;
left
=
width
-
dealign
;
/* Care for small copies. */
if
(
dealign
>
width
)
{
mask_first
^=
(
1ul
<<
(
dealign
-
width
))
-
1
;
left
=
0
;
}
/* Next copy full words at a time. */
n32
=
left
/
32
;
left
%=
32
;
/* Finally copy the unaligned head of the span. */
mask_last
=
-
1
<<
(
32
-
left
);
tga_regs
=
par
->
tga_regs_base
;
tga_fb
=
par
->
tga_fb_base
;
/* Set up the MODE and PIXELSHIFT registers. */
__raw_writel
(
TGA_MODE_SBM_8BPP
|
TGA_MODE_COPY
,
tga_regs
+
TGA_MODE_REG
);
__raw_writel
(
0
,
tga_regs
+
TGA_PIXELSHIFT_REG
);
wmb
();
for
(
i
=
0
;
i
<
height
;
++
i
)
{
unsigned
long
j
;
void
*
sfb
,
*
dfb
;
sfb
=
tga_fb
+
sepos
;
dfb
=
tga_fb
+
depos
;
if
(
mask_first
)
{
__raw_writel
(
mask_first
,
sfb
);
wmb
();
__raw_writel
(
mask_first
,
dfb
);
wmb
();
}
for
(
j
=
0
;
j
<
n32
;
++
j
)
{
sfb
-=
32
;
dfb
-=
32
;
__raw_writel
(
0xffffffff
,
sfb
);
wmb
();
__raw_writel
(
0xffffffff
,
dfb
);
wmb
();
}
if
(
mask_last
)
{
sfb
-=
32
;
dfb
-=
32
;
__raw_writel
(
mask_last
,
sfb
);
wmb
();
__raw_writel
(
mask_last
,
dfb
);
wmb
();
}
sepos
+=
yincr
;
depos
+=
yincr
;
}
/* Reset the MODE register to normal. */
__raw_writel
(
TGA_MODE_SBM_8BPP
|
TGA_MODE_SIMPLE
,
tga_regs
+
TGA_MODE_REG
);
}
static
void
tgafb_copyarea
(
struct
fb_info
*
info
,
struct
fb_copyarea
*
area
)
{
unsigned
long
dx
,
dy
,
width
,
height
,
sx
,
sy
,
vxres
,
vyres
;
unsigned
long
line_length
,
bpp
;
dx
=
area
->
dx
;
dy
=
area
->
dy
;
width
=
area
->
width
;
height
=
area
->
height
;
sx
=
area
->
sx
;
sy
=
area
->
sy
;
vxres
=
info
->
var
.
xres_virtual
;
vyres
=
info
->
var
.
yres_virtual
;
line_length
=
info
->
fix
.
line_length
;
/* The top left corners must be in the virtual screen. */
if
(
dx
>
vxres
||
sx
>
vxres
||
dy
>
vyres
||
sy
>
vyres
)
return
;
/* Clip the destination. */
if
(
dx
+
width
>
vxres
)
width
=
vxres
-
dx
;
if
(
dy
+
height
>
vyres
)
height
=
vyres
-
dy
;
/* The source must be completely inside the virtual screen. */
if
(
sx
+
width
>
vxres
||
sy
+
height
>
vyres
)
return
;
bpp
=
info
->
var
.
bits_per_pixel
;
/* Detect copies of the entire line. */
if
(
width
*
(
bpp
>>
3
)
==
line_length
)
{
if
(
bpp
==
8
)
copyarea_line_8bpp
(
info
,
dy
,
sy
,
height
,
width
);
else
copyarea_line_32bpp
(
info
,
dy
,
sy
,
height
,
width
);
}
/* ??? The documentation is unclear to me exactly how the pixelshift
register works in 32bpp mode. Since I don't have hardware to test,
give up for now and fall back on the generic routines. */
else
if
(
bpp
==
32
)
cfb_copyarea
(
info
,
area
);
/* Detect overlapping source and destination that requires
a backward copy. */
else
if
(
dy
==
sy
&&
dx
>
sx
&&
dx
<
sx
+
width
)
copyarea_backward_8bpp
(
info
,
dx
,
dy
,
sx
,
sy
,
height
,
width
,
line_length
,
area
);
else
copyarea_foreward_8bpp
(
info
,
dx
,
dy
,
sx
,
sy
,
height
,
width
,
line_length
);
}
/*
* Initialisation
*/
...
...
@@ -911,7 +1356,7 @@ tgafb_init_fix(struct fb_info *info)
info
->
fix
.
smem_start
=
(
size_t
)
par
->
tga_fb_base
;
info
->
fix
.
smem_len
=
info
->
fix
.
line_length
*
par
->
yres
;
info
->
fix
.
mmio_start
=
(
size_t
)
par
->
tga_regs_base
;
info
->
fix
.
mmio_len
=
0x1000
;
/* Is this sufficient? */
info
->
fix
.
mmio_len
=
512
;
info
->
fix
.
xpanstep
=
0
;
info
->
fix
.
ypanstep
=
0
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment