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
250883f3
Commit
250883f3
authored
Feb 26, 2003
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[FRAMEBUFFER]: Convert creatorfb to new APIs.
parent
743b21c5
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1173 additions
and
1333 deletions
+1173
-1333
drivers/video/Kconfig
drivers/video/Kconfig
+4
-4
drivers/video/Makefile
drivers/video/Makefile
+12
-8
drivers/video/fbmem.c
drivers/video/fbmem.c
+5
-9
drivers/video/ffb.c
drivers/video/ffb.c
+1046
-0
drivers/video/sbusfb.c
drivers/video/sbusfb.c
+0
-1165
drivers/video/sbuslib.c
drivers/video/sbuslib.c
+85
-0
drivers/video/sbuslib.h
drivers/video/sbuslib.h
+21
-0
include/video/sbusfb.h
include/video/sbusfb.h
+0
-147
No files found.
drivers/video/Kconfig
View file @
250883f3
...
...
@@ -809,12 +809,12 @@ config FB_SBUS
help
Say Y if you want support for SBUS or UPA based frame buffer device.
config FB_
CREATOR
bool "Creator/Creator3D support"
config FB_
FFB
bool "Creator/Creator3D
/Elite3D
support"
depends on FB_SBUS && SPARC64
help
This is the frame buffer device driver for the Creator
and Creator3D
graphics boards.
This is the frame buffer device driver for the Creator
, Creator3D,
and Elite3D
graphics boards.
config FB_TCX
bool "TCX (SS4/SS5 only) support"
...
...
drivers/video/Makefile
View file @
250883f3
...
...
@@ -48,14 +48,6 @@ obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \
obj-$(CONFIG_FB_VIRGE)
+=
virgefb.o
obj-$(CONFIG_FB_G364)
+=
g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_FM2)
+=
fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_CREATOR)
+=
creatorfb.o sbusfb.o
obj-$(CONFIG_FB_CGSIX)
+=
cgsixfb.o sbusfb.o
obj-$(CONFIG_FB_BWTWO)
+=
bwtwofb.o sbusfb.o
obj-$(CONFIG_FB_CGTHREE)
+=
cgthreefb.o sbusfb.o
obj-$(CONFIG_FB_TCX)
+=
tcxfb.o sbusfb.o
obj-$(CONFIG_FB_CGFOURTEEN)
+=
cgfourteenfb.o sbusfb.o
obj-$(CONFIG_FB_P9100)
+=
p9100fb.o sbusfb.o
obj-$(CONFIG_FB_LEO)
+=
leofb.o sbusfb.o
obj-$(CONFIG_FB_STI)
+=
stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_PMAG_BA)
+=
pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_PMAGB_B)
+=
pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
...
...
@@ -78,6 +70,18 @@ obj-$(CONFIG_FB_E1355) += epson1355fb.o
obj-$(CONFIG_FB_PVR2)
+=
pvr2fb.o
obj-$(CONFIG_FB_VOODOO1)
+=
sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
# One by one these are being converted over to the new APIs
#obj-$(CONFIG_FB_CREATOR) += creatorfb.o sbusfb.o
#obj-$(CONFIG_FB_CGSIX) += cgsixfb.o sbusfb.o
#obj-$(CONFIG_FB_BWTWO) += bwtwofb.o sbusfb.o
#obj-$(CONFIG_FB_CGTHREE) += cgthreefb.o sbusfb.o
#obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
#obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
#obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
#obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
obj-$(CONFIG_FB_FFB)
+=
ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
# Files generated that shall be removed upon make clean
clean-files
:=
promcon_tbl.c
...
...
drivers/video/fbmem.c
View file @
250883f3
...
...
@@ -103,8 +103,6 @@ extern int hgafb_setup(char*);
extern
int
matroxfb_init
(
void
);
extern
int
matroxfb_setup
(
char
*
);
extern
int
hpfb_init
(
void
);
extern
int
sbusfb_init
(
void
);
extern
int
sbusfb_setup
(
char
*
);
extern
int
control_init
(
void
);
extern
int
control_setup
(
char
*
);
extern
int
platinum_init
(
void
);
...
...
@@ -146,6 +144,8 @@ extern int sstfb_init(void);
extern
int
sstfb_setup
(
char
*
);
extern
int
i810fb_init
(
void
);
extern
int
i810fb_setup
(
char
*
);
extern
int
ffb_init
(
void
);
extern
int
ffb_setup
(
char
*
);
static
struct
{
const
char
*
name
;
...
...
@@ -153,13 +153,6 @@ static struct {
int
(
*
setup
)(
char
*
);
}
fb_drivers
[]
__initdata
=
{
#ifdef CONFIG_FB_SBUS
/*
* Sbusfb must be initialized _before_ other frame buffer devices that
* use PCI probing
*/
{
"sbus"
,
sbusfb_init
,
sbusfb_setup
},
#endif
/*
* Chipset specific drivers that use resource management
*/
...
...
@@ -244,6 +237,9 @@ static struct {
#ifdef CONFIG_FB_STI
{
"stifb"
,
stifb_init
,
stifb_setup
},
#endif
#ifdef CONFIG_FB_FFB
{
"ffb"
,
ffb_init
,
ffb_setup
},
#endif
/*
* Generic drivers that are used as fallbacks
...
...
drivers/video/
creator
fb.c
→
drivers/video/
f
fb.c
View file @
250883f3
/* $Id: creatorfb.c,v 1.37 2001/10/16 05:44:44 davem Exp $
* creatorfb.c: Creator/Creator3D frame buffer driver
/* ffb.c: Creator/Elite3D frame buffer driver
*
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
*
* Driver layout based loosely on tgafb.c, see that file for credits.
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/
selection
.h>
#include <
video/sbusfb
.h>
#include <linux/
fb
.h>
#include <linux/mm.h>
#include <
linux/timer
.h>
#include <asm/io.h>
#include <asm/upa.h>
#include <asm/oplib.h>
#include "sbuslib.h"
/*
* Local functions.
*/
static
int
ffb_check_var
(
struct
fb_var_screeninfo
*
,
struct
fb_info
*
);
static
int
ffb_set_par
(
struct
fb_info
*
);
static
int
ffb_setcolreg
(
unsigned
,
unsigned
,
unsigned
,
unsigned
,
unsigned
,
struct
fb_info
*
);
static
int
ffb_blank
(
int
,
struct
fb_info
*
);
static
void
ffb_init_fix
(
struct
fb_info
*
);
static
void
ffb_imageblit
(
struct
fb_info
*
,
struct
fb_image
*
);
static
void
ffb_fillrect
(
struct
fb_info
*
,
struct
fb_fillrect
*
);
static
void
ffb_copyarea
(
struct
fb_info
*
,
struct
fb_copyarea
*
);
static
int
ffb_sync
(
struct
fb_info
*
);
static
int
ffb_mmap
(
struct
fb_info
*
,
struct
file
*
,
struct
vm_area_struct
*
);
/*
* Frame buffer operations
*/
static
struct
fb_ops
ffb_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_check_var
=
ffb_check_var
,
.
fb_set_par
=
ffb_set_par
,
.
fb_setcolreg
=
ffb_setcolreg
,
.
fb_blank
=
ffb_blank
,
.
fb_fillrect
=
ffb_fillrect
,
.
fb_copyarea
=
ffb_copyarea
,
.
fb_imageblit
=
ffb_imageblit
,
.
fb_sync
=
ffb_sync
,
.
fb_mmap
=
ffb_mmap
,
/* XXX Use FFB hw cursor once fb cursor API is better understood... */
.
fb_cursor
=
soft_cursor
,
};
/* Register layout and definitions */
#define FFB_SFB8R_VOFF 0x00000000
#define FFB_SFB8G_VOFF 0x00400000
#define FFB_SFB8B_VOFF 0x00800000
...
...
@@ -132,6 +170,8 @@
#define FFB_PPC_CS_CONST 0x000003
#define FFB_ROP_NEW 0x83
#define FFB_ROP_OLD 0x85
#define FFB_ROP_NEW_XOR_OLD 0x86
#define FFB_UCSR_FIFO_MASK 0x00000fff
#define FFB_UCSR_FB_BUSY 0x01000000
...
...
@@ -287,493 +327,529 @@ struct ffb_fbc {
volatile
u32
mer
;
};
static
__inline__
void
FFBFifo
(
struct
fb_info_sbusfb
*
fb
,
int
n
)
struct
ffb_dac
{
volatile
u32
type
;
volatile
u32
value
;
volatile
u32
type2
;
volatile
u32
value2
;
};
struct
ffb_par
{
spinlock_t
lock
;
struct
ffb_fbc
*
fbc
;
struct
ffb_dac
*
dac
;
u32
flags
;
#define FFB_FLAG_AFB 0x00000001
#define FFB_FLAG_BLANKED 0x00000002
u32
fg_cache
__attribute__
((
aligned
(
8
)));
u32
bg_cache
;
u32
rop_cache
;
int
fifo_cache
;
unsigned
long
physbase
;
unsigned
long
fbsize
;
char
name
[
64
];
int
prom_node
;
int
prom_parent_node
;
int
dac_rev
;
int
board_type
;
struct
list_head
list
;
};
#undef FFB_DO_DEBUG_LOG
#ifdef FFB_DO_DEBUG_LOG
#define FFB_DEBUG_LOG_ENTS 32
static
struct
ffb_log
{
int
op
;
#define OP_FILLRECT 1
#define OP_IMAGEBLIT 2
int
depth
,
x
,
y
,
w
,
h
;
}
ffb_debug_log
[
FFB_DEBUG_LOG_ENTS
];
static
int
ffb_debug_log_ent
;
static
void
ffb_do_log
(
unsigned
long
unused
)
{
int
i
;
for
(
i
=
0
;
i
<
FFB_DEBUG_LOG_ENTS
;
i
++
)
{
struct
ffb_log
*
p
=
&
ffb_debug_log
[
i
];
printk
(
"FFB_LOG: OP[%s] depth(%d) x(%d) y(%d) w(%d) h(%d)
\n
"
,
(
p
->
op
==
OP_FILLRECT
?
"FILLRECT"
:
"IMAGEBLIT"
),
p
->
depth
,
p
->
x
,
p
->
y
,
p
->
w
,
p
->
h
);
}
}
static
struct
timer_list
ffb_log_timer
=
TIMER_INITIALIZER
(
ffb_do_log
,
0
,
0
);
static
void
ffb_log
(
int
op
,
int
depth
,
int
x
,
int
y
,
int
w
,
int
h
)
{
if
(
ffb_debug_log_ent
<
FFB_DEBUG_LOG_ENTS
)
{
struct
ffb_log
*
p
=
&
ffb_debug_log
[
ffb_debug_log_ent
];
if
(
ffb_debug_log_ent
!=
0
&&
p
[
-
1
].
op
==
op
&&
p
[
-
1
].
depth
==
depth
)
return
;
p
->
op
=
op
;
p
->
depth
=
depth
;
p
->
x
=
x
;
p
->
y
=
y
;
p
->
w
=
w
;
p
->
h
=
h
;
if
(
++
ffb_debug_log_ent
==
FFB_DEBUG_LOG_ENTS
)
{
ffb_log_timer
.
expires
=
jiffies
+
2
;
add_timer
(
&
ffb_log_timer
);
}
}
}
#else
#define ffb_log(a,b,c,d,e,f) do { } while(0)
#endif
#undef FORCE_WAIT_EVERY_ROP
static
void
FFBFifo
(
struct
ffb_par
*
par
,
int
n
)
{
struct
ffb_fbc
*
fbc
;
int
cache
=
fb
->
s
.
ffb
.
fifo_cache
;
int
cache
=
par
->
fifo_cache
;
if
(
cache
-
n
<
0
)
{
fbc
=
fb
->
s
.
ffb
.
fbc
;
fbc
=
par
->
fbc
;
do
{
cache
=
(
upa_readl
(
&
fbc
->
ucsr
)
&
FFB_UCSR_FIFO_MASK
)
-
8
;
}
while
(
cache
-
n
<
0
);
}
fb
->
s
.
ffb
.
fifo_cache
=
cache
-
n
;
par
->
fifo_cache
=
cache
-
n
;
}
static
__inline__
void
FFBWait
(
struct
ffb_fbc
*
ffb
)
static
void
FFBWait
(
struct
ffb_par
*
par
)
{
struct
ffb_fbc
*
fbc
;
int
limit
=
10000
;
fbc
=
par
->
fbc
;
do
{
if
((
upa_readl
(
&
f
fb
->
ucsr
)
&
FFB_UCSR_ALL_BUSY
)
==
0
)
if
((
upa_readl
(
&
f
bc
->
ucsr
)
&
FFB_UCSR_ALL_BUSY
)
==
0
)
break
;
if
((
upa_readl
(
&
f
fb
->
ucsr
)
&
FFB_UCSR_ALL_ERRORS
)
!=
0
)
{
upa_writel
(
FFB_UCSR_ALL_ERRORS
,
&
f
fb
->
ucsr
);
if
((
upa_readl
(
&
f
bc
->
ucsr
)
&
FFB_UCSR_ALL_ERRORS
)
!=
0
)
{
upa_writel
(
FFB_UCSR_ALL_ERRORS
,
&
f
bc
->
ucsr
);
}
udelay
(
10
);
}
while
(
--
limit
>
0
);
}
struct
ffb_dac
{
volatile
u32
type
;
volatile
u32
value
;
volatile
u32
type2
;
volatile
u32
value2
;
};
static
int
ffb_sync
(
struct
fb_info
*
p
)
{
struct
ffb_par
*
par
=
(
struct
ffb_par
*
)
p
->
par
;
static
struct
sbus_mmap_map
ffb_mmap_map
[]
=
{
{
FFB_SFB8R_VOFF
,
FFB_SFB8R_POFF
,
0x0400000
},
{
FFB_SFB8G_VOFF
,
FFB_SFB8G_POFF
,
0x0400000
},
{
FFB_SFB8B_VOFF
,
FFB_SFB8B_POFF
,
0x0400000
},
{
FFB_SFB8X_VOFF
,
FFB_SFB8X_POFF
,
0x0400000
},
{
FFB_SFB32_VOFF
,
FFB_SFB32_POFF
,
0x1000000
},
{
FFB_SFB64_VOFF
,
FFB_SFB64_POFF
,
0x2000000
},
{
FFB_FBC_REGS_VOFF
,
FFB_FBC_REGS_POFF
,
0x0002000
},
{
FFB_BM_FBC_REGS_VOFF
,
FFB_BM_FBC_REGS_POFF
,
0x0002000
},
{
FFB_DFB8R_VOFF
,
FFB_DFB8R_POFF
,
0x0400000
},
{
FFB_DFB8G_VOFF
,
FFB_DFB8G_POFF
,
0x0400000
},
{
FFB_DFB8B_VOFF
,
FFB_DFB8B_POFF
,
0x0400000
},
{
FFB_DFB8X_VOFF
,
FFB_DFB8X_POFF
,
0x0400000
},
{
FFB_DFB24_VOFF
,
FFB_DFB24_POFF
,
0x1000000
},
{
FFB_DFB32_VOFF
,
FFB_DFB32_POFF
,
0x1000000
},
{
FFB_FBC_KREGS_VOFF
,
FFB_FBC_KREGS_POFF
,
0x0002000
},
{
FFB_DAC_VOFF
,
FFB_DAC_POFF
,
0x0002000
},
{
FFB_PROM_VOFF
,
FFB_PROM_POFF
,
0x0010000
},
{
FFB_EXP_VOFF
,
FFB_EXP_POFF
,
0x0002000
},
{
FFB_DFB422A_VOFF
,
FFB_DFB422A_POFF
,
0x0800000
},
{
FFB_DFB422AD_VOFF
,
FFB_DFB422AD_POFF
,
0x0800000
},
{
FFB_DFB24B_VOFF
,
FFB_DFB24B_POFF
,
0x1000000
},
{
FFB_DFB422B_VOFF
,
FFB_DFB422B_POFF
,
0x0800000
},
{
FFB_DFB422BD_VOFF
,
FFB_DFB422BD_POFF
,
0x0800000
},
{
FFB_SFB16Z_VOFF
,
FFB_SFB16Z_POFF
,
0x0800000
},
{
FFB_SFB8Z_VOFF
,
FFB_SFB8Z_POFF
,
0x0800000
},
{
FFB_SFB422_VOFF
,
FFB_SFB422_POFF
,
0x0800000
},
{
FFB_SFB422D_VOFF
,
FFB_SFB422D_POFF
,
0x0800000
},
{
0
,
0
,
0
}
};
FFBWait
(
par
);
return
0
;
}
static
void
ffb_setup
(
struct
display
*
p
)
static
__inline__
void
ffb_rop
(
struct
ffb_par
*
par
,
u32
ro
p
)
{
p
->
next_line
=
8192
;
p
->
next_plane
=
0
;
if
(
par
->
rop_cache
!=
rop
)
{
FFBFifo
(
par
,
1
);
upa_writel
(
rop
,
&
par
->
fbc
->
rop
);
par
->
rop_cache
=
rop
;
}
}
static
void
ffb_clear
(
struct
vc_data
*
conp
,
struct
display
*
p
,
int
sy
,
int
sx
,
int
height
,
int
width
)
static
void
ffb_switch_from_graph
(
struct
ffb_par
*
par
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
p
->
fb_info
);
register
struct
ffb_fbc
*
fbc
=
fb
->
s
.
ffb
.
fbc
;
struct
ffb_fbc
*
fbc
=
par
->
fbc
;
unsigned
long
flags
;
u64
yx
,
hw
;
int
fg
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
fg
=
((
u32
*
)
p
->
dispsw_data
)[
attr_bgcol_ec
(
p
,
conp
)];
if
(
fg
!=
fb
->
s
.
ffb
.
fg_cache
)
{
FFBFifo
(
fb
,
5
);
upa_writel
(
fg
,
&
fbc
->
fg
);
fb
->
s
.
ffb
.
fg_cache
=
fg
;
}
else
FFBFifo
(
fb
,
4
);
if
(
fontheightlog
(
p
))
{
yx
=
(
u64
)
sy
<<
(
fontheightlog
(
p
)
+
32
);
hw
=
(
u64
)
height
<<
(
fontheightlog
(
p
)
+
32
);
}
else
{
yx
=
(
u64
)(
sy
*
fontheight
(
p
))
<<
32
;
hw
=
(
u64
)(
height
*
fontheight
(
p
))
<<
32
;
}
if
(
fontwidthlog
(
p
))
{
yx
+=
sx
<<
fontwidthlog
(
p
);
hw
+=
width
<<
fontwidthlog
(
p
);
}
else
{
yx
+=
sx
*
fontwidth
(
p
);
hw
+=
width
*
fontwidth
(
p
);
}
upa_writeq
(
yx
+
fb
->
s
.
ffb
.
yx_margin
,
&
fbc
->
by
);
upa_writeq
(
hw
,
&
fbc
->
bh
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
FFBWait
(
par
);
par
->
fifo_cache
=
0
;
FFBFifo
(
par
,
7
);
upa_writel
(
FFB_PPC_VCE_DISABLE
|
FFB_PPC_TBE_OPAQUE
|
FFB_PPC_APE_DISABLE
|
FFB_PPC_CS_CONST
,
&
fbc
->
ppc
);
upa_writel
(
0x2000707f
,
&
fbc
->
fbc
);
upa_writel
(
par
->
rop_cache
,
&
fbc
->
rop
);
upa_writel
(
0xffffffff
,
&
fbc
->
pmask
);
upa_writel
((
0
<<
16
)
|
(
32
<<
0
),
&
fbc
->
fontinc
);
upa_writel
(
par
->
fg_cache
,
&
fbc
->
fg
);
upa_writel
(
par
->
bg_cache
,
&
fbc
->
bg
);
FFBWait
(
par
);
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
}
static
void
ffb_fill
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
s
,
int
count
,
unsigned
short
*
boxes
)
/**
* ffb_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
ffb_fillrect
(
struct
fb_info
*
info
,
struct
fb_fillrect
*
rect
)
{
register
struct
ffb_fbc
*
fbc
=
fb
->
s
.
ffb
.
fbc
;
struct
ffb_par
*
par
=
(
struct
ffb_par
*
)
info
->
par
;
struct
ffb_fbc
*
fbc
=
par
->
fbc
;
unsigned
long
flags
;
int
fg
;
u32
fg
;
if
(
rect
->
rop
!=
ROP_COPY
&&
rect
->
rop
!=
ROP_XOR
)
BUG
();
ffb_log
(
OP_FILLRECT
,
0
,
rect
->
dx
,
rect
->
dy
,
rect
->
width
,
rect
->
height
);
fg
=
((
u32
*
)
info
->
pseudo_palette
)[
rect
->
color
];
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
fg
=
((
u32
*
)
p
->
dispsw_data
)[
attr_bgcol
(
p
,
s
)];
if
(
fg
!=
fb
->
s
.
ffb
.
fg_cache
)
{
FFBFifo
(
fb
,
1
);
if
(
fg
!=
par
->
fg_cache
)
{
FFBFifo
(
par
,
1
);
upa_writel
(
fg
,
&
fbc
->
fg
);
fb
->
s
.
ffb
.
fg_cache
=
fg
;
par
->
fg_cache
=
fg
;
}
while
(
count
--
>
0
)
{
FFBFifo
(
fb
,
4
);
upa_writel
(
boxes
[
1
],
&
fbc
->
by
);
upa_writel
(
boxes
[
0
],
&
fbc
->
bx
);
upa_writel
(
boxes
[
3
]
-
boxes
[
1
],
&
fbc
->
bh
);
upa_writel
(
boxes
[
2
]
-
boxes
[
0
],
&
fbc
->
bw
);
boxes
+=
4
;
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
ffb_rop
(
par
,
(
rect
->
rop
==
ROP_COPY
?
FFB_ROP_NEW
:
FFB_ROP_NEW_XOR_OLD
));
FFBFifo
(
par
,
5
);
upa_writel
(
FFB_DRAWOP_RECTANGLE
,
&
fbc
->
drawop
);
upa_writel
(
rect
->
dy
,
&
fbc
->
by
);
upa_writel
(
rect
->
dx
,
&
fbc
->
bx
);
upa_writel
(
rect
->
height
,
&
fbc
->
bh
);
upa_writel
(
rect
->
width
,
&
fbc
->
bw
);
#ifdef FORCE_WAIT_EVERY_ROP
FFBWait
(
par
);
#endif
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
}
static
void
ffb_putc
(
struct
vc_data
*
conp
,
struct
display
*
p
,
int
c
,
int
yy
,
int
xx
)
/**
* ffb_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.
*/
static
void
ffb_copyarea
(
struct
fb_info
*
info
,
struct
fb_copyarea
*
area
)
{
struct
f
b_info_sbusfb
*
fb
=
sbusfbinfo
(
p
->
fb_info
)
;
register
struct
ffb_fbc
*
fbc
=
fb
->
s
.
ffb
.
fbc
;
struct
f
fb_par
*
par
=
(
struct
ffb_par
*
)
info
->
par
;
struct
ffb_fbc
*
fbc
=
par
->
fbc
;
unsigned
long
flags
;
int
i
,
xy
;
u8
*
fd
;
u64
fgbg
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
if
(
fontheightlog
(
p
))
{
xy
=
(
yy
<<
(
16
+
fontheightlog
(
p
)));
i
=
((
c
&
p
->
charmask
)
<<
fontheightlog
(
p
));
}
else
{
xy
=
((
yy
*
fontheight
(
p
))
<<
16
);
i
=
(
c
&
p
->
charmask
)
*
fontheight
(
p
);
if
(
area
->
dx
!=
area
->
sx
||
area
->
dy
==
area
->
dy
)
{
cfb_copyarea
(
info
,
area
);
return
;
}
if
(
fontwidth
(
p
)
<=
8
)
fd
=
p
->
fontdata
+
i
;
else
fd
=
p
->
fontdata
+
(
i
<<
1
);
if
(
fontwidthlog
(
p
))
xy
+=
(
xx
<<
fontwidthlog
(
p
))
+
fb
->
s
.
ffb
.
xy_margin
;
else
xy
+=
(
xx
*
fontwidth
(
p
))
+
fb
->
s
.
ffb
.
xy_margin
;
fgbg
=
(((
u64
)(((
u32
*
)
p
->
dispsw_data
)[
attr_fgcol
(
p
,
c
)]))
<<
32
)
|
((
u32
*
)
p
->
dispsw_data
)[
attr_bgcol
(
p
,
c
)];
if
(
fgbg
!=
*
(
u64
*
)
&
fb
->
s
.
ffb
.
fg_cache
)
{
FFBFifo
(
fb
,
2
);
upa_writeq
(
fgbg
,
&
fbc
->
fg
);
*
(
u64
*
)
&
fb
->
s
.
ffb
.
fg_cache
=
fgbg
;
}
FFBFifo
(
fb
,
2
+
fontheight
(
p
));
upa_writel
(
xy
,
&
fbc
->
fontxy
);
upa_writel
(
fontwidth
(
p
),
&
fbc
->
fontw
);
if
(
fontwidth
(
p
)
<=
8
)
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
fd
++
<<
24
;
upa_writel
(
val
,
&
fbc
->
font
);
}
}
else
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
(
u16
*
)
fd
<<
16
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
upa_writel
(
val
,
&
fbc
->
font
);
fd
+=
2
;
}
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
ffb_rop
(
par
,
FFB_ROP_OLD
);
FFBFifo
(
par
,
7
);
upa_writel
(
FFB_DRAWOP_VSCROLL
,
&
fbc
->
drawop
);
upa_writel
(
area
->
sy
,
&
fbc
->
by
);
upa_writel
(
area
->
sx
,
&
fbc
->
bx
);
upa_writel
(
area
->
dy
,
&
fbc
->
dy
);
upa_writel
(
area
->
dx
,
&
fbc
->
dx
);
upa_writel
(
area
->
height
,
&
fbc
->
bh
);
upa_writel
(
area
->
width
,
&
fbc
->
bw
);
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
}
static
void
ffb_putcs
(
struct
vc_data
*
conp
,
struct
display
*
p
,
const
unsigned
short
*
s
,
int
count
,
int
yy
,
int
xx
)
/**
* ffb_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
ffb_imageblit
(
struct
fb_info
*
info
,
struct
fb_image
*
image
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
p
->
fb_info
);
register
struct
ffb_fbc
*
fbc
=
fb
->
s
.
ffb
.
fbc
;
struct
ffb_par
*
par
=
(
struct
ffb_par
*
)
info
->
par
;
struct
ffb_fbc
*
fbc
=
par
->
fbc
;
u8
*
data
=
(
u8
*
)
image
->
data
;
unsigned
long
flags
;
int
i
,
xy
;
u8
*
fd1
,
*
fd2
,
*
fd3
,
*
fd4
;
u16
c
;
u32
fg
,
bg
,
xy
;
u64
fgbg
;
int
i
,
width
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
c
=
scr_readw
(
s
);
fgbg
=
(((
u64
)(((
u32
*
)
p
->
dispsw_data
)[
attr_fgcol
(
p
,
c
)]))
<<
32
)
|
((
u32
*
)
p
->
dispsw_data
)[
attr_bgcol
(
p
,
c
)];
if
(
fgbg
!=
*
(
u64
*
)
&
fb
->
s
.
ffb
.
fg_cache
)
{
FFBFifo
(
fb
,
2
);
upa_writeq
(
fgbg
,
&
fbc
->
fg
);
*
(
u64
*
)
&
fb
->
s
.
ffb
.
fg_cache
=
fgbg
;
ffb_log
(
OP_IMAGEBLIT
,
image
->
depth
,
image
->
dx
,
image
->
dy
,
image
->
width
,
image
->
height
);
if
(
image
->
depth
>
1
)
{
cfb_imageblit
(
info
,
image
);
return
;
}
xy
=
fb
->
s
.
ffb
.
xy_margin
;
if
(
fontwidthlog
(
p
))
xy
+=
(
xx
<<
fontwidthlog
(
p
));
else
xy
+=
xx
*
fontwidth
(
p
);
if
(
fontheightlog
(
p
))
xy
+=
(
yy
<<
(
16
+
fontheightlog
(
p
)));
else
xy
+=
((
yy
*
fontheight
(
p
))
<<
16
);
if
(
fontwidth
(
p
)
<=
8
)
{
while
(
count
>=
4
)
{
count
-=
4
;
FFBFifo
(
fb
,
2
+
fontheight
(
p
));
upa_writel
(
4
*
fontwidth
(
p
),
&
fbc
->
fontw
);
upa_writel
(
xy
,
&
fbc
->
fontxy
);
if
(
fontheightlog
(
p
))
{
fd1
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
fd2
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
fd3
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
fd4
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
}
else
{
fd1
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
fd2
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
fd3
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
fd4
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
}
if
(
fontwidth
(
p
)
==
8
)
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
;
val
=
((
u32
)
*
fd4
++
)
|
((((
u32
)
*
fd3
++
)
|
((((
u32
)
*
fd2
++
)
|
(((
u32
)
*
fd1
++
)
<<
8
))
<<
8
))
<<
8
);
upa_writel
(
val
,
&
fbc
->
font
);
}
xy
+=
32
;
}
else
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
(((
u32
)
*
fd4
++
)
|
((((
u32
)
*
fd3
++
)
|
((((
u32
)
*
fd2
++
)
|
(((
u32
)
*
fd1
++
)
<<
fontwidth
(
p
)))
<<
fontwidth
(
p
)))
<<
fontwidth
(
p
)))
<<
(
24
-
3
*
fontwidth
(
p
));
upa_writel
(
val
,
&
fbc
->
font
);
}
xy
+=
4
*
fontwidth
(
p
);
}
}
}
else
{
while
(
count
>=
2
)
{
count
-=
2
;
FFBFifo
(
fb
,
2
+
fontheight
(
p
));
upa_writel
(
2
*
fontwidth
(
p
),
&
fbc
->
fontw
);
upa_writel
(
xy
,
&
fbc
->
fontxy
);
if
(
fontheightlog
(
p
))
{
fd1
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
(
fontheightlog
(
p
)
+
1
));
fd2
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
(
fontheightlog
(
p
)
+
1
));
}
else
{
fd1
=
p
->
fontdata
+
(((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
))
<<
1
);
fd2
=
p
->
fontdata
+
(((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
))
<<
1
);
}
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
((((
u32
)
*
(
u16
*
)
fd1
)
<<
fontwidth
(
p
))
|
((
u32
)
*
(
u16
*
)
fd2
))
<<
(
16
-
fontwidth
(
p
));
upa_writel
(
val
,
&
fbc
->
font
);
fd1
+=
2
;
fd2
+=
2
;
}
xy
+=
2
*
fontwidth
(
p
);
}
fg
=
((
u32
*
)
info
->
pseudo_palette
)[
image
->
fg_color
];
bg
=
((
u32
*
)
info
->
pseudo_palette
)[
image
->
bg_color
];
fgbg
=
((
u64
)
fg
<<
32
)
|
(
u64
)
bg
;
xy
=
(
image
->
dy
<<
16
)
|
image
->
dx
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
if
(
fgbg
!=
*
(
u64
*
)
&
par
->
fg_cache
)
{
FFBFifo
(
par
,
2
);
upa_writeq
(
fgbg
,
&
fbc
->
fg
);
*
(
u64
*
)
&
par
->
fg_cache
=
fgbg
;
}
while
(
count
)
{
count
--
;
FFBFifo
(
fb
,
2
+
fontheight
(
p
));
upa_writel
(
fontwidth
(
p
),
&
fbc
->
fontw
);
ffb_rop
(
par
,
FFB_ROP_NEW
);
for
(
i
=
0
;
i
<
image
->
height
;
i
++
)
{
width
=
image
->
width
;
FFBFifo
(
par
,
1
);
upa_writel
(
xy
,
&
fbc
->
fontxy
);
if
(
fontheightlog
(
p
))
i
=
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
else
i
=
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
if
(
fontwidth
(
p
)
<=
8
)
{
fd1
=
p
->
fontdata
+
i
;
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
fd1
++
<<
24
;
xy
+=
(
1
<<
16
);
upa_writel
(
val
,
&
fbc
->
font
);
}
}
else
{
fd1
=
p
->
fontdata
+
(
i
<<
1
);
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
(
u16
*
)
fd1
<<
16
;
while
(
width
>=
32
)
{
u32
val
;
FFBFifo
(
par
,
2
);
upa_writel
(
32
,
&
fbc
->
fontw
);
val
=
((
u32
)
data
[
0
]
<<
24
)
|
((
u32
)
data
[
1
]
<<
16
)
|
((
u32
)
data
[
2
]
<<
8
)
|
((
u32
)
data
[
3
]
<<
0
);
upa_writel
(
val
,
&
fbc
->
font
);
data
+=
4
;
width
-=
32
;
}
upa_writel
(
val
,
&
fbc
->
font
);
fd1
+=
2
;
if
(
width
)
{
u32
val
;
FFBFifo
(
par
,
2
);
upa_writel
(
width
,
&
fbc
->
fontw
);
if
(
width
<=
8
)
{
val
=
(
u32
)
data
[
0
]
<<
24
;
data
+=
1
;
}
else
if
(
width
<=
16
)
{
val
=
((
u32
)
data
[
0
]
<<
24
)
|
((
u32
)
data
[
1
]
<<
16
);
data
+=
2
;
}
else
{
val
=
((
u32
)
data
[
0
]
<<
24
)
|
((
u32
)
data
[
1
]
<<
16
)
|
((
u32
)
data
[
2
]
<<
8
);
data
+=
3
;
}
upa_writel
(
val
,
&
fbc
->
font
);
}
xy
+=
fontwidth
(
p
);
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
#ifdef FORCE_WAIT_EVERY_ROP
FFBWait
(
par
);
#endif
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
}
static
void
ffb_
revc
(
struct
display
*
p
,
int
xx
,
int
yy
)
static
void
ffb_
fixup_var_rgb
(
struct
fb_var_screeninfo
*
var
)
{
/* Not used if hw cursor */
var
->
red
.
offset
=
0
;
var
->
red
.
length
=
8
;
var
->
green
.
offset
=
8
;
var
->
green
.
length
=
8
;
var
->
blue
.
offset
=
16
;
var
->
blue
.
length
=
8
;
var
->
transp
.
offset
=
0
;
var
->
transp
.
length
=
0
;
}
#if 0
static int ffb_blank(struct fb_info_sbusfb *fb)
/**
* ffb_check_var - Optional function. Validates a var passed in.
* @var: frame buffer variable screen structure
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
ffb_check_var
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
struct ffb_dac *dac = fb->s.ffb.dac;
unsigned long flags;
u32 tmp;
if
(
var
->
bits_per_pixel
!=
32
)
return
-
EINVAL
;
if
(
var
->
xres_virtual
!=
var
->
xres
||
var
->
yres_virtual
!=
var
->
yres
)
return
-
EINVAL
;
if
(
var
->
nonstd
)
return
-
EINVAL
;
if
((
var
->
vmode
&
FB_VMODE_MASK
)
!=
FB_VMODE_NONINTERLACED
)
return
-
EINVAL
;
if
(
var
->
xres
!=
info
->
var
.
xres
||
var
->
yres
!=
info
->
var
.
yres
)
return
-
EINVAL
;
ffb_fixup_var_rgb
(
var
);
spin_lock_irqsave(&fb->lock, flags);
upa_writel(0x6000, &dac->type);
tmp = (upa_readl(&dac->value) & ~0x1);
upa_writel(0x6000, &dac->type);
upa_writel(tmp, &dac->value);
spin_unlock_irqrestore(&fb->lock, flags);
return
0
;
}
#endif
static
int
ffb_unblank
(
struct
fb_info_sbusfb
*
fb
)
/**
* ffb_set_par - Optional function. Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
ffb_set_par
(
struct
fb_info
*
info
)
{
struct
ffb_dac
*
dac
=
fb
->
s
.
ffb
.
dac
;
unsigned
long
flags
;
u32
tmp
;
return
0
;
}
/**
* ffb_setcolreg - Optional function. Sets a color register.
* @regno: boolean, 0 copy local, 1 get_user() function
* @red: frame buffer colormap structure
* @green: The green value which can be up to 16 bits wide
* @blue: The blue value which can be up to 16 bits wide.
* @transp: If supported the alpha value which can be up to 16 bits wide.
* @info: frame buffer info structure
*/
static
int
ffb_setcolreg
(
unsigned
regno
,
unsigned
red
,
unsigned
green
,
unsigned
blue
,
unsigned
transp
,
struct
fb_info
*
info
)
{
u32
value
;
if
(
regno
>=
256
)
return
1
;
red
>>=
8
;
green
>>=
8
;
blue
>>=
8
;
value
=
(
blue
<<
16
)
|
(
green
<<
8
)
|
red
;
((
u32
*
)
info
->
pseudo_palette
)[
regno
]
=
value
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
upa_writel
(
0x6000
,
&
dac
->
type
);
tmp
=
(
upa_readl
(
&
dac
->
value
)
|
0x1
);
upa_writel
(
0x6000
,
&
dac
->
type
);
upa_writel
(
tmp
,
&
dac
->
value
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
}
static
void
ffb_loadcmap
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
index
,
int
count
)
/**
* ffb_blank - Optional function. Blanks the display.
* @blank_mode: the blank mode we want.
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
ffb_blank
(
int
blank
,
struct
fb_info
*
info
)
{
struct
ffb_dac
*
dac
=
fb
->
s
.
ffb
.
dac
;
struct
ffb_par
*
par
=
(
struct
ffb_par
*
)
info
->
par
;
struct
ffb_dac
*
dac
=
par
->
dac
;
unsigned
long
flags
;
int
i
,
j
=
count
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
upa_writel
(
0x2000
|
index
,
&
dac
->
type
);
for
(
i
=
index
;
j
--
;
i
++
)
{
u32
val
;
/* Feed the colors in :)) */
val
=
((
fb
->
color_map
CM
(
i
,
0
)))
|
((
fb
->
color_map
CM
(
i
,
1
))
<<
8
)
|
((
fb
->
color_map
CM
(
i
,
2
))
<<
16
);
upa_writel
(
val
,
&
dac
->
value
);
u32
tmp
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
FFBWait
(
par
);
switch
(
blank
)
{
case
0
:
/* Unblanking */
upa_writel
(
0x6000
,
&
dac
->
type
);
tmp
=
(
upa_readl
(
&
dac
->
value
)
|
0x1
);
upa_writel
(
0x6000
,
&
dac
->
type
);
upa_writel
(
tmp
,
&
dac
->
value
);
par
->
flags
&=
~
FFB_FLAG_BLANKED
;
break
;
case
1
:
/* Normal blanking */
case
2
:
/* VESA blank (vsync off) */
case
3
:
/* VESA blank (hsync off) */
case
4
:
/* Poweroff */
upa_writel
(
0x6000
,
&
dac
->
type
);
tmp
=
(
upa_readl
(
&
dac
->
value
)
&
~
0x1
);
upa_writel
(
0x6000
,
&
dac
->
type
);
upa_writel
(
tmp
,
&
dac
->
value
);
par
->
flags
|=
FFB_FLAG_BLANKED
;
break
;
}
if
(
!
p
)
goto
out
;
for
(
i
=
index
,
j
=
count
;
i
<
16
&&
j
--
;
i
++
)
((
u32
*
)
p
->
dispsw_data
)[
i
]
=
((
fb
->
color_map
CM
(
i
,
0
)))
|
((
fb
->
color_map
CM
(
i
,
1
))
<<
8
)
|
((
fb
->
color_map
CM
(
i
,
2
))
<<
16
);
out:
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
return
0
;
}
static
struct
display_switch
ffb_dispsw
__initdata
=
{
.
setup
=
ffb_setup
,
.
bmove
=
fbcon_redraw_bmove
,
.
clear
=
ffb_clear
,
.
putc
=
ffb_putc
,
.
putcs
=
ffb_putcs
,
.
revc
=
ffb_revc
,
.
fontwidthmask
=
FONTWIDTHRANGE
(
1
,
16
)
/* Allow fontwidths up to 16 */
static
struct
sbus_mmap_map
ffb_mmap_map
[]
=
{
{
FFB_SFB8R_VOFF
,
FFB_SFB8R_POFF
,
0x0400000
},
{
FFB_SFB8G_VOFF
,
FFB_SFB8G_POFF
,
0x0400000
},
{
FFB_SFB8B_VOFF
,
FFB_SFB8B_POFF
,
0x0400000
},
{
FFB_SFB8X_VOFF
,
FFB_SFB8X_POFF
,
0x0400000
},
{
FFB_SFB32_VOFF
,
FFB_SFB32_POFF
,
0x1000000
},
{
FFB_SFB64_VOFF
,
FFB_SFB64_POFF
,
0x2000000
},
{
FFB_FBC_REGS_VOFF
,
FFB_FBC_REGS_POFF
,
0x0002000
},
{
FFB_BM_FBC_REGS_VOFF
,
FFB_BM_FBC_REGS_POFF
,
0x0002000
},
{
FFB_DFB8R_VOFF
,
FFB_DFB8R_POFF
,
0x0400000
},
{
FFB_DFB8G_VOFF
,
FFB_DFB8G_POFF
,
0x0400000
},
{
FFB_DFB8B_VOFF
,
FFB_DFB8B_POFF
,
0x0400000
},
{
FFB_DFB8X_VOFF
,
FFB_DFB8X_POFF
,
0x0400000
},
{
FFB_DFB24_VOFF
,
FFB_DFB24_POFF
,
0x1000000
},
{
FFB_DFB32_VOFF
,
FFB_DFB32_POFF
,
0x1000000
},
{
FFB_FBC_KREGS_VOFF
,
FFB_FBC_KREGS_POFF
,
0x0002000
},
{
FFB_DAC_VOFF
,
FFB_DAC_POFF
,
0x0002000
},
{
FFB_PROM_VOFF
,
FFB_PROM_POFF
,
0x0010000
},
{
FFB_EXP_VOFF
,
FFB_EXP_POFF
,
0x0002000
},
{
FFB_DFB422A_VOFF
,
FFB_DFB422A_POFF
,
0x0800000
},
{
FFB_DFB422AD_VOFF
,
FFB_DFB422AD_POFF
,
0x0800000
},
{
FFB_DFB24B_VOFF
,
FFB_DFB24B_POFF
,
0x1000000
},
{
FFB_DFB422B_VOFF
,
FFB_DFB422B_POFF
,
0x0800000
},
{
FFB_DFB422BD_VOFF
,
FFB_DFB422BD_POFF
,
0x0800000
},
{
FFB_SFB16Z_VOFF
,
FFB_SFB16Z_POFF
,
0x0800000
},
{
FFB_SFB8Z_VOFF
,
FFB_SFB8Z_POFF
,
0x0800000
},
{
FFB_SFB422_VOFF
,
FFB_SFB422_POFF
,
0x0800000
},
{
FFB_SFB422D_VOFF
,
FFB_SFB422D_POFF
,
0x0800000
},
{
0
,
0
,
0
}
};
static
void
ffb_margins
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
x_margin
,
int
y_margin
)
static
int
ffb_mmap
(
struct
fb_info
*
info
,
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
register
struct
ffb_fbc
*
fbc
=
fb
->
s
.
ffb
.
fbc
;
unsigned
long
flags
;
struct
ffb_par
*
par
=
(
struct
ffb_par
*
)
info
->
par
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
fb
->
s
.
ffb
.
xy_margin
=
(
y_margin
<<
16
)
+
x_margin
;
fb
->
s
.
ffb
.
yx_margin
=
(((
u64
)
y_margin
)
<<
32
)
+
x_margin
;
fb
->
info
.
screen_base
+=
8192
*
(
y_margin
-
fb
->
y_margin
)
+
4
*
(
x_margin
-
fb
->
x_margin
);
FFBWait
(
fbc
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
sbusfb_mmap_helper
(
ffb_mmap_map
,
par
->
physbase
,
par
->
fbsize
,
0
,
vma
);
}
static
__inline__
void
__ffb_curs_enable
(
struct
fb_info_sbusfb
*
fb
,
int
enable
)
{
struct
ffb_dac
*
dac
=
fb
->
s
.
ffb
.
dac
;
u32
val
;
upa_writel
(
0x100
,
&
dac
->
type2
);
if
(
fb
->
s
.
ffb
.
dac_rev
<=
2
)
{
val
=
enable
?
3
:
0
;
}
else
{
val
=
enable
?
0
:
3
;
}
upa_writel
(
val
,
&
dac
->
value2
);
}
/*
* Initialisation
*/
static
void
ffb_setcursormap
(
struct
fb_info_sbusfb
*
fb
,
u8
*
red
,
u8
*
green
,
u8
*
blue
)
static
void
ffb_init_fix
(
struct
fb_info
*
info
)
{
struct
ffb_dac
*
dac
=
fb
->
s
.
ffb
.
dac
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
__ffb_curs_enable
(
fb
,
0
);
upa_writel
(
0x102
,
&
dac
->
type2
);
upa_writel
((
red
[
0
]
|
(
green
[
0
]
<<
8
)
|
(
blue
[
0
]
<<
16
)),
&
dac
->
value2
);
upa_writel
((
red
[
1
]
|
(
green
[
1
]
<<
8
)
|
(
blue
[
1
]
<<
16
)),
&
dac
->
value2
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
}
struct
ffb_par
*
par
=
(
struct
ffb_par
*
)
info
->
par
;
const
char
*
ffb_type_name
;
/* Set cursor shape */
static
void
ffb_setcurshape
(
struct
fb_info_sbusfb
*
fb
)
{
struct
ffb_dac
*
dac
=
fb
->
s
.
ffb
.
dac
;
unsigned
long
flags
;
int
i
,
j
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
__ffb_curs_enable
(
fb
,
0
);
for
(
j
=
0
;
j
<
2
;
j
++
)
{
u32
val
=
j
?
0
:
0x80
;
upa_writel
(
val
,
&
dac
->
type2
);
for
(
i
=
0
;
i
<
0x40
;
i
++
)
{
if
(
fb
->
cursor
.
size
.
fbx
<=
32
)
{
upa_writel
(
fb
->
cursor
.
bits
[
j
][
i
],
&
dac
->
value2
);
upa_writel
(
0
,
&
dac
->
value2
);
}
else
{
upa_writel
(
fb
->
cursor
.
bits
[
j
][
2
*
i
],
&
dac
->
value2
);
upa_writel
(
fb
->
cursor
.
bits
[
j
][
2
*
i
+
1
],
&
dac
->
value2
);
}
}
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
}
if
(
!
(
par
->
flags
&
FFB_FLAG_AFB
))
{
if
((
par
->
board_type
&
0x7
)
==
0x3
)
ffb_type_name
=
"Creator 3D"
;
else
ffb_type_name
=
"Creator"
;
}
else
ffb_type_name
=
"Elite 3D"
;
/* Load cursor information */
static
void
ffb_setcursor
(
struct
fb_info_sbusfb
*
fb
)
{
struct
ffb_dac
*
dac
=
fb
->
s
.
ffb
.
dac
;
struct
cg_cursor
*
c
=
&
fb
->
cursor
;
unsigned
long
flags
;
u32
val
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
upa_writel
(
0x104
,
&
dac
->
type2
);
/* Should this be just 0x7ff??
Should I do some margin handling and setcurshape in that case? */
val
=
(((
c
->
cpos
.
fby
-
c
->
chot
.
fby
)
&
0xffff
)
<<
16
)
|
((
c
->
cpos
.
fbx
-
c
->
chot
.
fbx
)
&
0xffff
);
upa_writel
(
val
,
&
dac
->
value2
);
__ffb_curs_enable
(
fb
,
fb
->
cursor
.
enable
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
}
strncpy
(
info
->
fix
.
id
,
ffb_type_name
,
sizeof
(
info
->
fix
.
id
)
-
1
);
info
->
fix
.
id
[
sizeof
(
info
->
fix
.
id
)
-
1
]
=
0
;
static
void
ffb_switch_from_graph
(
struct
fb_info_sbusfb
*
fb
)
{
register
struct
ffb_fbc
*
fbc
=
fb
->
s
.
ffb
.
fbc
;
unsigned
long
flags
;
info
->
fix
.
type
=
FB_TYPE_PACKED_PIXELS
;
info
->
fix
.
visual
=
FB_VISUAL_TRUECOLOR
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
FFBWait
(
fbc
);
fb
->
s
.
ffb
.
fifo_cache
=
0
;
FFBFifo
(
fb
,
8
);
upa_writel
(
FFB_PPC_VCE_DISABLE
|
FFB_PPC_TBE_OPAQUE
|
FFB_PPC_APE_DISABLE
|
FFB_PPC_CS_CONST
,
&
fbc
->
ppc
);
upa_writel
(
0x2000707f
,
&
fbc
->
fbc
);
upa_writel
(
FFB_ROP_NEW
,
&
fbc
->
rop
);
upa_writel
(
FFB_DRAWOP_RECTANGLE
,
&
fbc
->
drawop
);
upa_writel
(
0xffffffff
,
&
fbc
->
pmask
);
upa_writel
(
0x10000
,
&
fbc
->
fontinc
);
upa_writel
(
fb
->
s
.
ffb
.
fg_cache
,
&
fbc
->
fg
);
upa_writel
(
fb
->
s
.
ffb
.
bg_cache
,
&
fbc
->
bg
);
FFBWait
(
fbc
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
}
/* Framebuffer length is the same regardless of resolution. */
info
->
fix
.
line_length
=
8192
;
static
int
__init
ffb_rasterimg
(
struct
fb_info
*
info
,
int
start
)
{
ffb_switch_from_graph
(
sbusfbinfo
(
info
));
return
0
;
info
->
fix
.
accel
=
FB_ACCEL_SUN_CREATOR
;
}
static
char
idstring
[
60
]
__initdata
=
{
0
};
static
int
__init
creator_apply_upa_parent_ranges
(
int
parent
,
struct
linux_prom64_registers
*
regs
)
static
int
ffb_apply_upa_parent_ranges
(
int
parent
,
struct
linux_prom64_registers
*
regs
)
{
struct
linux_prom64_ranges
ranges
[
PROMREG_MAX
];
char
name
[
128
];
...
...
@@ -803,126 +879,168 @@ static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom6
return
1
;
}
char
__init
*
creatorfb_init
(
struct
fb_info_sbusfb
*
fb
)
struct
all_info
{
struct
fb_info
info
;
struct
ffb_par
par
;
u32
pseudo_palette
[
256
];
struct
list_head
list
;
};
static
LIST_HEAD
(
ffb_list
);
static
void
ffb_init_one
(
int
node
,
int
parent
)
{
struct
fb_fix_screeninfo
*
fix
=
&
fb
->
info
.
fix
;
struct
fb_var_screeninfo
*
var
=
&
fb
->
info
.
var
;
struct
display
*
disp
=
&
fb
->
disp
;
struct
fbtype
*
type
=
&
fb
->
type
;
struct
linux_prom64_registers
regs
[
2
*
PROMREG_MAX
];
int
i
,
afb
=
0
;
unsigned
int
btype
;
char
name
[
64
];
struct
fb_ops
*
fbops
;
if
(
prom_getproperty
(
fb
->
prom_node
,
"reg"
,
(
void
*
)
regs
,
sizeof
(
regs
))
<=
0
)
return
NULL
;
if
(
creator_apply_upa_parent_ranges
(
fb
->
prom_parent
,
&
regs
[
0
]))
return
NULL
;
disp
->
dispsw_data
=
(
void
*
)
kmalloc
(
16
*
sizeof
(
u32
),
GFP_KERNEL
);
if
(
disp
->
dispsw_data
==
NULL
)
return
NULL
;
memset
(
disp
->
dispsw_data
,
0
,
16
*
sizeof
(
u32
));
fbops
=
kmalloc
(
sizeof
(
*
fbops
),
GFP_KERNEL
);
if
(
fbops
==
NULL
)
{
kfree
(
disp
->
dispsw_data
);
return
NULL
;
struct
ffb_fbc
*
fbc
;
struct
ffb_dac
*
dac
;
struct
all_info
*
all
;
if
(
prom_getproperty
(
node
,
"reg"
,
(
void
*
)
regs
,
sizeof
(
regs
))
<=
0
)
{
printk
(
"ffb: Cannot get reg device node property.
\n
"
);
return
;
}
*
fbops
=
*
fb
->
info
.
fbops
;
fbops
->
fb_rasterimg
=
ffb_rasterimg
;
fb
->
info
.
fbops
=
fbops
;
prom_getstring
(
fb
->
prom_node
,
"name"
,
name
,
sizeof
(
name
));
if
(
!
strcmp
(
name
,
"SUNW,afb"
))
afb
=
1
;
btype
=
prom_getintdefault
(
fb
->
prom_node
,
"board_type"
,
0
);
strcpy
(
fb
->
info
.
modename
,
"Creator"
);
if
(
!
afb
)
{
if
((
btype
&
7
)
==
3
)
strcpy
(
fix
->
id
,
"Creator 3D"
);
else
strcpy
(
fix
->
id
,
"Creator"
);
}
else
strcpy
(
fix
->
id
,
"Elite 3D"
);
fix
->
visual
=
FB_VISUAL_TRUECOLOR
;
fix
->
line_length
=
8192
;
fix
->
accel
=
FB_ACCEL_SUN_CREATOR
;
var
->
bits_per_pixel
=
32
;
var
->
green
.
offset
=
8
;
var
->
blue
.
offset
=
16
;
var
->
accel_flags
=
FB_ACCELF_TEXT
;
disp
->
scrollmode
=
SCROLL_YREDRAW
;
fb
->
info
.
screen_base
=
(
char
*
)(
regs
[
0
].
phys_addr
)
+
FFB_DFB24_POFF
+
8192
*
fb
->
y_margin
+
4
*
fb
->
x_margin
;
fb
->
s
.
ffb
.
xy_margin
=
(
fb
->
y_margin
<<
16
)
+
fb
->
x_margin
;
fb
->
s
.
ffb
.
yx_margin
=
(((
u64
)
fb
->
y_margin
)
<<
32
)
+
fb
->
x_margin
;
fb
->
s
.
ffb
.
fbc
=
(
struct
ffb_fbc
*
)(
regs
[
0
].
phys_addr
+
FFB_FBC_REGS_POFF
);
fb
->
s
.
ffb
.
dac
=
(
struct
ffb_dac
*
)(
regs
[
0
].
phys_addr
+
FFB_DAC_POFF
);
fb
->
dispsw
=
ffb_dispsw
;
fb
->
margins
=
ffb_margins
;
fb
->
loadcmap
=
ffb_loadcmap
;
fb
->
setcursor
=
ffb_setcursor
;
fb
->
setcursormap
=
ffb_setcursormap
;
fb
->
setcurshape
=
ffb_setcurshape
;
fb
->
switch_from_graph
=
ffb_switch_from_graph
;
fb
->
fill
=
ffb_fill
;
#if 0
/* XXX Can't enable this for now, I've seen cases
* XXX where the VC was blanked, and Xsun24 was started
* XXX via a remote login, the sunfb code did not
* XXX unblank creator when it was mmap'd for some
* XXX reason, investigate later... -DaveM
*/
fb->blank = ffb_blank;
fb->unblank = ffb_unblank;
#endif
/* If there are any read errors or fifo overflow conditions,
* clear them now.
*/
if
((
upa_readl
(
&
fb
->
s
.
ffb
.
fbc
->
ucsr
)
&
FFB_UCSR_ALL_ERRORS
)
!=
0
)
upa_writel
(
FFB_UCSR_ALL_ERRORS
,
&
fb
->
s
.
ffb
.
fbc
->
ucsr
);
ffb_switch_from_graph
(
fb
);
fb
->
physbase
=
regs
[
0
].
phys_addr
;
fb
->
mmap_map
=
ffb_mmap_map
;
fb
->
cursor
.
hwsize
.
fbx
=
64
;
fb
->
cursor
.
hwsize
.
fby
=
64
;
type
->
fb_depth
=
24
;
upa_writel
(
0x8000
,
&
fb
->
s
.
ffb
.
dac
->
type
);
fb
->
s
.
ffb
.
dac_rev
=
(
upa_readl
(
&
fb
->
s
.
ffb
.
dac
->
value
)
>>
0x1c
);
i
=
prom_getintdefault
(
fb
->
prom_node
,
"board_type"
,
8
);
if
(
ffb_apply_upa_parent_ranges
(
parent
,
&
regs
[
0
]))
{
printk
(
"ffb: Cannot apply parent ranges to regs.
\n
"
);
return
;
}
all
=
kmalloc
(
sizeof
(
*
all
),
GFP_KERNEL
);
if
(
!
all
)
{
printk
(
KERN_ERR
"ffb: Cannot allocate memory.
\n
"
);
return
;
}
memset
(
all
,
0
,
sizeof
(
*
all
));
INIT_LIST_HEAD
(
&
all
->
list
);
spin_lock_init
(
&
all
->
par
.
lock
);
all
->
par
.
fbc
=
(
struct
ffb_fbc
*
)(
regs
[
0
].
phys_addr
+
FFB_FBC_REGS_POFF
);
all
->
par
.
dac
=
(
struct
ffb_dac
*
)(
regs
[
0
].
phys_addr
+
FFB_DAC_POFF
);
all
->
par
.
rop_cache
=
FFB_ROP_NEW
;
all
->
par
.
physbase
=
regs
[
0
].
phys_addr
;
all
->
par
.
prom_node
=
node
;
all
->
par
.
prom_parent_node
=
parent
;
all
->
info
.
node
=
NODEV
;
all
->
info
.
flags
=
FBINFO_FLAG_DEFAULT
;
all
->
info
.
fbops
=
&
ffb_ops
;
all
->
info
.
screen_base
=
(
char
*
)
all
->
par
.
physbase
+
FFB_DFB24_POFF
;
all
->
info
.
currcon
=
-
1
;
all
->
info
.
par
=
&
all
->
par
;
all
->
info
.
pseudo_palette
=
all
->
pseudo_palette
;
sbusfb_fill_var
(
&
all
->
info
.
var
,
all
->
par
.
prom_node
,
32
);
all
->
par
.
fbsize
=
PAGE_ALIGN
(
all
->
info
.
var
.
xres
*
all
->
info
.
var
.
yres
*
4
);
ffb_fixup_var_rgb
(
&
all
->
info
.
var
);
all
->
info
.
var
.
accel_flags
=
FB_ACCELF_TEXT
;
prom_getstring
(
node
,
"name"
,
all
->
par
.
name
,
sizeof
(
all
->
par
.
name
));
if
(
!
strcmp
(
all
->
par
.
name
,
"SUNW,afb"
))
all
->
par
.
flags
|=
FFB_FLAG_AFB
;
all
->
par
.
board_type
=
prom_getintdefault
(
node
,
"board_type"
,
0
);
fbc
=
all
->
par
.
fbc
;
if
((
upa_readl
(
&
fbc
->
ucsr
)
&
FFB_UCSR_ALL_ERRORS
)
!=
0
)
upa_writel
(
FFB_UCSR_ALL_ERRORS
,
&
fbc
->
ucsr
);
ffb_switch_from_graph
(
&
all
->
par
);
dac
=
all
->
par
.
dac
;
upa_writel
(
0x8000
,
&
dac
->
type
);
all
->
par
.
dac_rev
=
upa_readl
(
&
dac
->
value
)
>>
0x1c
;
sprintf
(
idstring
,
"%s at %016lx type %d DAC %d"
,
fix
->
id
,
regs
[
0
].
phys_addr
,
i
,
fb
->
s
.
ffb
.
dac_rev
);
/* Elite3D has different DAC revision numbering, and no DAC revisions
have the reversed meaning of cursor enable */
if
(
afb
)
fb
->
s
.
ffb
.
dac_rev
=
10
;
* have the reversed meaning of cursor enable.
*/
if
(
all
->
par
.
flags
&
FFB_FLAG_AFB
)
all
->
par
.
dac_rev
=
10
;
/* Unblank it just to be sure. When there are multiple
* FFB/AFB cards in the system, or it is not the OBP
* chosen console, it will have video outputs off in
* the DAC.
*/
ffb_
unblank
(
fb
);
ffb_
blank
(
0
,
&
all
->
info
);
return
idstring
;
if
(
fb_alloc_cmap
(
&
all
->
info
.
cmap
,
256
,
0
))
{
printk
(
KERN_ERR
"ffb: Could not allocate color map.
\n
"
);
kfree
(
all
);
return
;
}
ffb_set_par
(
&
all
->
info
);
ffb_init_fix
(
&
all
->
info
);
if
(
register_framebuffer
(
&
all
->
info
)
<
0
)
{
printk
(
KERN_ERR
"ffb: Could not register framebuffer.
\n
"
);
fb_dealloc_cmap
(
&
all
->
info
.
cmap
);
kfree
(
all
);
return
;
}
list_add
(
&
all
->
list
,
&
ffb_list
);
printk
(
"ffb: %s at %016lx type %d DAC %d
\n
"
,
((
all
->
par
.
flags
&
FFB_FLAG_AFB
)
?
"AFB"
:
"FFB"
),
regs
[
0
].
phys_addr
,
all
->
par
.
board_type
,
all
->
par
.
dac_rev
);
}
static
void
ffb_scan_siblings
(
int
root
)
{
int
node
,
child
;
child
=
prom_getchild
(
root
);
for
(
node
=
prom_searchsiblings
(
child
,
"SUNW,ffb"
);
node
;
node
=
prom_searchsiblings
(
prom_getsibling
(
node
),
"SUNW,ffb"
))
ffb_init_one
(
node
,
root
);
for
(
node
=
prom_searchsiblings
(
child
,
"SUNW,afb"
);
node
;
node
=
prom_searchsiblings
(
prom_getsibling
(
node
),
"SUNW,afb"
))
ffb_init_one
(
node
,
root
);
}
int
__init
ffb_init
(
void
)
{
int
root
;
ffb_scan_siblings
(
prom_root_node
);
root
=
prom_getchild
(
prom_root_node
);
for
(
root
=
prom_searchsiblings
(
root
,
"upa"
);
root
;
root
=
prom_searchsiblings
(
prom_getsibling
(
root
),
"upa"
))
ffb_scan_siblings
(
root
);
return
0
;
}
void
__exit
ffb_exit
(
void
)
{
struct
list_head
*
pos
,
*
tmp
;
list_for_each_safe
(
pos
,
tmp
,
&
ffb_list
)
{
struct
all_info
*
all
=
list_entry
(
pos
,
typeof
(
*
all
),
list
);
unregister_framebuffer
(
&
all
->
info
);
fb_dealloc_cmap
(
&
all
->
info
.
cmap
);
kfree
(
all
);
}
}
int
__init
ffb_setup
(
char
*
arg
)
{
/* No cmdline options yet... */
return
0
;
}
#ifdef MODULE
module_init
(
ffb_init
);
module_exit
(
ffb_exit
);
#endif
MODULE_DESCRIPTION
(
"framebuffer driver for Creator/Elite3D chipsets"
);
MODULE_AUTHOR
(
"David S. Miller <davem@redhat.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/video/sbusfb.c
deleted
100644 → 0
View file @
743b21c5
/*
* linux/drivers/video/sbusfb.c -- SBUS or UPA based frame buffer device
*
* Copyright (C) 1998 Jakub Jelinek
*
* This driver is partly based on the Open Firmware console driver
*
* Copyright (C) 1997 Geert Uytterhoeven
*
* and SPARC console subsystem
*
* Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com)
* Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
* Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*
* 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/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/selection.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/kd.h>
#include <linux/vt_kern.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
/* io_remap_page_range() */
#include <video/sbusfb.h>
#define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5)
#define CURSOR_SHAPE 1
#define CURSOR_BLINK 2
/*
* Interface used by the world
*/
int
sbusfb_init
(
void
);
int
sbusfb_setup
(
char
*
);
static
int
defx_margin
=
-
1
,
defy_margin
=
-
1
;
static
char
fontname
[
40
]
__initdata
=
{
0
};
static
int
curblink
__initdata
=
1
;
static
struct
{
int
depth
;
int
xres
,
yres
;
int
x_margin
,
y_margin
;
}
def_margins
[]
=
{
{
8
,
1280
,
1024
,
64
,
80
},
{
8
,
1152
,
1024
,
64
,
80
},
{
8
,
1152
,
900
,
64
,
18
},
{
8
,
1024
,
768
,
0
,
0
},
{
8
,
800
,
600
,
16
,
12
},
{
8
,
640
,
480
,
0
,
0
},
{
1
,
1152
,
900
,
8
,
18
},
{
0
},
};
static
int
sbusfb_open
(
struct
fb_info
*
info
,
int
user
);
static
int
sbusfb_release
(
struct
fb_info
*
info
,
int
user
);
static
int
sbusfb_mmap
(
struct
fb_info
*
info
,
struct
file
*
file
,
struct
vm_area_struct
*
vma
);
static
int
sbusfb_set_var
(
struct
fb_var_screeninfo
*
var
,
int
con
,
struct
fb_info
*
info
);
static
int
sbusfb_get_cmap
(
struct
fb_cmap
*
cmap
,
int
kspc
,
int
con
,
struct
fb_info
*
info
);
static
int
sbusfb_set_cmap
(
struct
fb_cmap
*
cmap
,
int
kspc
,
int
con
,
struct
fb_info
*
info
);
static
int
sbusfb_setcolreg
(
u_int
regno
,
u_int
red
,
u_int
green
,
u_int
blue
,
u_int
transp
,
struct
fb_info
*
info
);
static
int
sbusfb_blank
(
int
blank
,
struct
fb_info
*
info
);
static
int
sbusfb_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
u_int
cmd
,
u_long
arg
,
int
con
,
struct
fb_info
*
info
);
static
void
sbusfb_cursor
(
struct
display
*
p
,
int
mode
,
int
x
,
int
y
);
static
void
sbusfb_clear_margin
(
struct
display
*
p
,
int
s
);
/*
* Interface to the low level console driver
*/
static
int
sbusfbcon_switch
(
int
con
,
struct
fb_info
*
info
);
static
int
sbusfbcon_updatevar
(
int
con
,
struct
fb_info
*
info
);
/*
* Internal routines
*/
static
int
sbusfb_getcolreg
(
u_int
regno
,
u_int
*
red
,
u_int
*
green
,
u_int
*
blue
,
u_int
*
transp
,
struct
fb_info
*
info
);
static
struct
fb_ops
sbusfb_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_open
=
sbusfb_open
,
.
fb_release
=
sbusfb_release
,
.
fb_set_var
=
sbusfb_set_var
,
.
fb_get_cmap
=
sbusfb_get_cmap
,
.
fb_set_cmap
=
sbusfb_set_cmap
,
.
fb_setcolreg
=
sbusfb_setcolreg
,
.
fb_blank
=
sbusfb_blank
,
.
fb_ioctl
=
sbusfb_ioctl
,
.
fb_mmap
=
sbusfb_mmap
,
};
/*
* Open/Release the frame buffer device
*/
static
int
sbusfb_open
(
struct
fb_info
*
info
,
int
user
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
if
(
user
)
{
if
(
fb
->
open
==
0
)
{
fb
->
mmaped
=
0
;
fb
->
vtconsole
=
-
1
;
}
fb
->
open
++
;
}
else
fb
->
consolecnt
++
;
return
0
;
}
static
int
sbusfb_release
(
struct
fb_info
*
info
,
int
user
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
if
(
user
)
{
fb
->
open
--
;
if
(
fb
->
open
==
0
)
{
if
(
fb
->
vtconsole
!=
-
1
)
{
vt_cons
[
fb
->
vtconsole
]
->
vc_mode
=
KD_TEXT
;
if
(
fb
->
mmaped
)
{
fb
->
graphmode
--
;
sbusfb_clear_margin
(
&
fb_display
[
fb
->
vtconsole
],
0
);
}
}
if
(
fb
->
reset
)
fb
->
reset
(
fb
);
}
}
else
fb
->
consolecnt
--
;
return
0
;
}
static
unsigned
long
sbusfb_mmapsize
(
struct
fb_info_sbusfb
*
fb
,
long
size
)
{
if
(
size
==
SBUS_MMAP_EMPTY
)
return
0
;
if
(
size
>=
0
)
return
size
;
return
fb
->
type
.
fb_size
*
(
-
size
);
}
static
int
sbusfb_mmap
(
struct
fb_info
*
info
,
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
unsigned
int
size
,
page
,
r
,
map_size
;
unsigned
long
map_offset
=
0
;
unsigned
long
off
;
int
i
;
size
=
vma
->
vm_end
-
vma
->
vm_start
;
if
(
vma
->
vm_pgoff
>
(
~
0UL
>>
PAGE_SHIFT
))
return
-
EINVAL
;
off
=
vma
->
vm_pgoff
<<
PAGE_SHIFT
;
/* To stop the swapper from even considering these pages */
vma
->
vm_flags
|=
(
VM_SHM
|
VM_LOCKED
);
/* Each page, see which map applies */
for
(
page
=
0
;
page
<
size
;
){
map_size
=
0
;
for
(
i
=
0
;
fb
->
mmap_map
[
i
].
size
;
i
++
)
if
(
fb
->
mmap_map
[
i
].
voff
==
off
+
page
)
{
map_size
=
sbusfb_mmapsize
(
fb
,
fb
->
mmap_map
[
i
].
size
);
#ifdef __sparc_v9__
#define POFF_MASK (PAGE_MASK|0x1UL)
#else
#define POFF_MASK (PAGE_MASK)
#endif
map_offset
=
(
fb
->
physbase
+
fb
->
mmap_map
[
i
].
poff
)
&
POFF_MASK
;
break
;
}
if
(
!
map_size
){
page
+=
PAGE_SIZE
;
continue
;
}
if
(
page
+
map_size
>
size
)
map_size
=
size
-
page
;
r
=
io_remap_page_range
(
vma
,
vma
->
vm_start
+
page
,
map_offset
,
map_size
,
vma
->
vm_page_prot
,
fb
->
iospace
);
if
(
r
)
return
-
EAGAIN
;
page
+=
map_size
;
}
vma
->
vm_flags
|=
VM_IO
;
if
(
!
fb
->
mmaped
)
{
int
lastconsole
=
0
;
if
(
info
->
display_fg
)
lastconsole
=
info
->
display_fg
->
vc_num
;
fb
->
mmaped
=
1
;
if
(
fb
->
consolecnt
&&
fb_display
[
lastconsole
].
fb_info
==
info
)
{
fb
->
vtconsole
=
lastconsole
;
fb
->
graphmode
++
;
vt_cons
[
lastconsole
]
->
vc_mode
=
KD_GRAPHICS
;
vc_cons
[
lastconsole
].
d
->
vc_sw
->
con_cursor
(
vc_cons
[
lastconsole
].
d
,
CM_ERASE
);
}
else
if
(
fb
->
unblank
&&
!
fb
->
blanked
)
(
*
fb
->
unblank
)(
fb
);
}
return
0
;
}
static
void
sbusfb_clear_margin
(
struct
display
*
p
,
int
s
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfod
(
p
);
if
(
fb
->
switch_from_graph
)
(
*
fb
->
switch_from_graph
)(
fb
);
if
(
fb
->
fill
)
{
unsigned
short
rects
[
16
];
rects
[
0
]
=
0
;
rects
[
1
]
=
0
;
rects
[
2
]
=
fb
->
info
.
var
.
xres_virtual
;
rects
[
3
]
=
fb
->
y_margin
;
rects
[
4
]
=
0
;
rects
[
5
]
=
fb
->
y_margin
;
rects
[
6
]
=
fb
->
x_margin
;
rects
[
7
]
=
fb
->
info
.
var
.
yres_virtual
;
rects
[
8
]
=
fb
->
info
.
var
.
xres_virtual
-
fb
->
x_margin
;
rects
[
9
]
=
fb
->
y_margin
;
rects
[
10
]
=
fb
->
info
.
var
.
xres_virtual
;
rects
[
11
]
=
fb
->
info
.
var
.
yres_virtual
;
rects
[
12
]
=
fb
->
x_margin
;
rects
[
13
]
=
fb
->
info
.
var
.
yres_virtual
-
fb
->
y_margin
;
rects
[
14
]
=
fb
->
info
.
var
.
xres_virtual
-
fb
->
x_margin
;
rects
[
15
]
=
fb
->
info
.
var
.
yres_virtual
;
(
*
fb
->
fill
)(
fb
,
p
,
s
,
4
,
rects
);
}
else
{
unsigned
char
*
fb_base
=
fb
->
info
.
screen_base
,
*
q
;
int
skip_bytes
=
fb
->
y_margin
*
fb
->
info
.
var
.
xres_virtual
;
int
scr_size
=
fb
->
info
.
var
.
xres_virtual
*
fb
->
info
.
var
.
yres_virtual
;
int
h
,
he
,
incr
,
size
;
he
=
fb
->
info
.
var
.
yres
;
if
(
fb
->
info
.
var
.
bits_per_pixel
==
1
)
{
fb_base
-=
(
skip_bytes
+
fb
->
x_margin
)
/
8
;
skip_bytes
/=
8
;
scr_size
/=
8
;
fb_memset255
(
fb_base
,
skip_bytes
-
fb
->
x_margin
/
8
);
fb_memset255
(
fb_base
+
scr_size
-
skip_bytes
+
fb
->
x_margin
/
8
,
skip_bytes
-
fb
->
x_margin
/
8
);
incr
=
fb
->
info
.
var
.
xres_virtual
/
8
;
size
=
fb
->
x_margin
/
8
*
2
;
for
(
q
=
fb_base
+
skip_bytes
-
fb
->
x_margin
/
8
,
h
=
0
;
h
<=
he
;
q
+=
incr
,
h
++
)
fb_memset255
(
q
,
size
);
}
else
{
fb_base
-=
(
skip_bytes
+
fb
->
x_margin
);
fb_memset
(
fb_base
,
attr_bgcol
(
p
,
s
),
skip_bytes
-
fb
->
x_margin
);
fb_memset
(
fb_base
+
scr_size
-
skip_bytes
+
fb
->
x_margin
,
attr_bgcol
(
p
,
s
),
skip_bytes
-
fb
->
x_margin
);
incr
=
fb
->
info
.
var
.
xres_virtual
;
size
=
fb
->
x_margin
*
2
;
for
(
q
=
fb_base
+
skip_bytes
-
fb
->
x_margin
,
h
=
0
;
h
<=
he
;
q
+=
incr
,
h
++
)
fb_memset
(
q
,
attr_bgcol
(
p
,
s
),
size
);
}
}
}
static
void
sbusfb_disp_setup
(
struct
display
*
p
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfod
(
p
);
if
(
fb
->
setup
)
fb
->
setup
(
p
);
sbusfb_clear_margin
(
p
,
0
);
}
/*
* Set the User Defined Part of the Display
*/
static
int
sbusfb_set_var
(
struct
fb_var_screeninfo
*
var
,
int
con
,
struct
fb_info
*
info
)
{
struct
display
*
display
;
int
activate
=
var
->
activate
;
if
(
con
>=
0
)
display
=
&
fb_display
[
con
];
else
display
=
info
->
disp
;
/* simple check for equality until fully implemented -E */
if
((
activate
&
FB_ACTIVATE_MASK
)
==
FB_ACTIVATE_NOW
)
{
if
(
display
->
var
.
xres
!=
var
->
xres
||
display
->
var
.
yres
!=
var
->
yres
||
display
->
var
.
xres_virtual
!=
var
->
xres_virtual
||
display
->
var
.
yres_virtual
!=
var
->
yres_virtual
||
display
->
var
.
bits_per_pixel
!=
var
->
bits_per_pixel
||
display
->
var
.
accel_flags
!=
var
->
accel_flags
)
{
return
-
EINVAL
;
}
}
return
0
;
}
/*
* Hardware cursor
*/
static
int
sbus_hw_scursor
(
struct
fbcursor
*
cursor
,
struct
fb_info_sbusfb
*
fb
)
{
int
op
;
int
i
,
bytes
=
0
;
struct
fbcursor
f
;
char
red
[
2
],
green
[
2
],
blue
[
2
];
if
(
copy_from_user
(
&
f
,
cursor
,
sizeof
(
struct
fbcursor
)))
return
-
EFAULT
;
op
=
f
.
set
;
if
(
op
&
FB_CUR_SETSHAPE
){
if
((
u32
)
f
.
size
.
fbx
>
fb
->
cursor
.
hwsize
.
fbx
)
return
-
EINVAL
;
if
((
u32
)
f
.
size
.
fby
>
fb
->
cursor
.
hwsize
.
fby
)
return
-
EINVAL
;
if
(
f
.
size
.
fbx
>
32
)
bytes
=
f
.
size
.
fby
<<
3
;
else
bytes
=
f
.
size
.
fby
<<
2
;
}
if
(
op
&
FB_CUR_SETCMAP
){
if
(
f
.
cmap
.
index
||
f
.
cmap
.
count
!=
2
)
return
-
EINVAL
;
if
(
copy_from_user
(
red
,
f
.
cmap
.
red
,
2
)
||
copy_from_user
(
green
,
f
.
cmap
.
green
,
2
)
||
copy_from_user
(
blue
,
f
.
cmap
.
blue
,
2
))
return
-
EFAULT
;
}
if
(
op
&
FB_CUR_SETCMAP
)
(
*
fb
->
setcursormap
)
(
fb
,
red
,
green
,
blue
);
if
(
op
&
FB_CUR_SETSHAPE
){
u32
u
;
fb
->
cursor
.
size
=
f
.
size
;
memset
((
void
*
)
&
fb
->
cursor
.
bits
,
0
,
sizeof
(
fb
->
cursor
.
bits
));
if
(
copy_from_user
(
fb
->
cursor
.
bits
[
0
],
f
.
mask
,
bytes
)
||
copy_from_user
(
fb
->
cursor
.
bits
[
1
],
f
.
image
,
bytes
))
return
-
EFAULT
;
if
(
f
.
size
.
fbx
<=
32
)
{
u
=
0xffffffff
<<
(
32
-
f
.
size
.
fbx
);
for
(
i
=
fb
->
cursor
.
size
.
fby
-
1
;
i
>=
0
;
i
--
)
{
fb
->
cursor
.
bits
[
0
][
i
]
&=
u
;
fb
->
cursor
.
bits
[
1
][
i
]
&=
fb
->
cursor
.
bits
[
0
][
i
];
}
}
else
{
u
=
0xffffffff
<<
(
64
-
f
.
size
.
fbx
);
for
(
i
=
fb
->
cursor
.
size
.
fby
-
1
;
i
>=
0
;
i
--
)
{
fb
->
cursor
.
bits
[
0
][
2
*
i
+
1
]
&=
u
;
fb
->
cursor
.
bits
[
1
][
2
*
i
]
&=
fb
->
cursor
.
bits
[
0
][
2
*
i
];
fb
->
cursor
.
bits
[
1
][
2
*
i
+
1
]
&=
fb
->
cursor
.
bits
[
0
][
2
*
i
+
1
];
}
}
(
*
fb
->
setcurshape
)
(
fb
);
}
if
(
op
&
(
FB_CUR_SETCUR
|
FB_CUR_SETPOS
|
FB_CUR_SETHOT
)){
if
(
op
&
FB_CUR_SETCUR
)
fb
->
cursor
.
enable
=
f
.
enable
;
if
(
op
&
FB_CUR_SETPOS
)
fb
->
cursor
.
cpos
=
f
.
pos
;
if
(
op
&
FB_CUR_SETHOT
)
fb
->
cursor
.
chot
=
f
.
hot
;
(
*
fb
->
setcursor
)
(
fb
);
}
return
0
;
}
static
unsigned
char
hw_cursor_cmap
[
2
]
=
{
0
,
0xff
};
static
void
sbusfb_cursor_timer_handler
(
unsigned
long
dev_addr
)
{
struct
fb_info_sbusfb
*
fb
=
(
struct
fb_info_sbusfb
*
)
dev_addr
;
if
(
!
fb
->
setcursor
)
return
;
if
(
fb
->
cursor
.
mode
&
CURSOR_BLINK
)
{
fb
->
cursor
.
enable
^=
1
;
fb
->
setcursor
(
fb
);
}
fb
->
cursor
.
timer
.
expires
=
jiffies
+
fb
->
cursor
.
blink_rate
;
add_timer
(
&
fb
->
cursor
.
timer
);
}
static
void
sbusfb_cursor
(
struct
display
*
p
,
int
mode
,
int
x
,
int
y
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfod
(
p
);
switch
(
mode
)
{
case
CM_ERASE
:
fb
->
cursor
.
mode
&=
~
CURSOR_BLINK
;
fb
->
cursor
.
enable
=
0
;
(
*
fb
->
setcursor
)(
fb
);
break
;
case
CM_MOVE
:
case
CM_DRAW
:
if
(
fb
->
cursor
.
mode
&
CURSOR_SHAPE
)
{
fb
->
cursor
.
size
.
fbx
=
fontwidth
(
p
);
fb
->
cursor
.
size
.
fby
=
fontheight
(
p
);
fb
->
cursor
.
chot
.
fbx
=
0
;
fb
->
cursor
.
chot
.
fby
=
0
;
fb
->
cursor
.
enable
=
1
;
memset
(
fb
->
cursor
.
bits
,
0
,
sizeof
(
fb
->
cursor
.
bits
));
fb
->
cursor
.
bits
[
0
][
fontheight
(
p
)
-
2
]
=
(
0xffffffff
<<
(
32
-
fontwidth
(
p
)));
fb
->
cursor
.
bits
[
1
][
fontheight
(
p
)
-
2
]
=
(
0xffffffff
<<
(
32
-
fontwidth
(
p
)));
fb
->
cursor
.
bits
[
0
][
fontheight
(
p
)
-
1
]
=
(
0xffffffff
<<
(
32
-
fontwidth
(
p
)));
fb
->
cursor
.
bits
[
1
][
fontheight
(
p
)
-
1
]
=
(
0xffffffff
<<
(
32
-
fontwidth
(
p
)));
(
*
fb
->
setcursormap
)
(
fb
,
hw_cursor_cmap
,
hw_cursor_cmap
,
hw_cursor_cmap
);
(
*
fb
->
setcurshape
)
(
fb
);
}
fb
->
cursor
.
mode
=
CURSOR_BLINK
;
if
(
fontwidthlog
(
p
))
fb
->
cursor
.
cpos
.
fbx
=
(
x
<<
fontwidthlog
(
p
))
+
fb
->
x_margin
;
else
fb
->
cursor
.
cpos
.
fbx
=
(
x
*
fontwidth
(
p
))
+
fb
->
x_margin
;
if
(
fontheightlog
(
p
))
fb
->
cursor
.
cpos
.
fby
=
(
y
<<
fontheightlog
(
p
))
+
fb
->
y_margin
;
else
fb
->
cursor
.
cpos
.
fby
=
(
y
*
fontheight
(
p
))
+
fb
->
y_margin
;
(
*
fb
->
setcursor
)(
fb
);
break
;
}
}
/*
* Get the Colormap
*/
static
int
sbusfb_get_cmap
(
struct
fb_cmap
*
cmap
,
int
kspc
,
int
con
,
struct
fb_info
*
info
)
{
if
(
!
info
->
display_fg
||
con
==
info
->
display_fg
->
vc_num
)
/* current console? */
return
fb_get_cmap
(
cmap
,
kspc
,
sbusfb_getcolreg
,
info
);
else
if
(
fb_display
[
con
].
cmap
.
len
)
/* non default colormap? */
fb_copy_cmap
(
&
fb_display
[
con
].
cmap
,
cmap
,
kspc
?
0
:
2
);
else
fb_copy_cmap
(
fb_default_cmap
(
1
<<
fb_display
[
con
].
var
.
bits_per_pixel
),
cmap
,
kspc
?
0
:
2
);
return
0
;
}
/*
* Set the Colormap
*/
static
int
sbusfb_set_cmap
(
struct
fb_cmap
*
cmap
,
int
kspc
,
int
con
,
struct
fb_info
*
info
)
{
int
err
;
struct
display
*
disp
;
if
(
con
>=
0
)
disp
=
&
fb_display
[
con
];
else
disp
=
info
->
disp
;
if
(
!
disp
->
cmap
.
len
)
{
/* no colormap allocated? */
if
((
err
=
fb_alloc_cmap
(
&
disp
->
cmap
,
1
<<
disp
->
var
.
bits_per_pixel
,
0
)))
return
err
;
}
if
(
con
==
info
->
currcon
)
{
/* current console? */
err
=
fb_set_cmap
(
cmap
,
kspc
,
info
);
if
(
!
err
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
if
(
fb
->
loadcmap
)
(
*
fb
->
loadcmap
)(
fb
,
&
fb_display
[
con
],
cmap
->
start
,
cmap
->
len
);
}
return
err
;
}
else
fb_copy_cmap
(
cmap
,
&
disp
->
cmap
,
kspc
?
0
:
1
);
return
0
;
}
static
int
sbusfb_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
u_int
cmd
,
u_long
arg
,
int
con
,
struct
fb_info
*
info
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
int
i
;
int
lastconsole
;
switch
(
cmd
){
case
FBIOGTYPE
:
/* return frame buffer type */
if
(
copy_to_user
((
struct
fbtype
*
)
arg
,
&
fb
->
type
,
sizeof
(
struct
fbtype
)))
return
-
EFAULT
;
break
;
case
FBIOGATTR
:
{
struct
fbgattr
*
fba
=
(
struct
fbgattr
*
)
arg
;
i
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
struct
fbgattr
));
if
(
i
)
return
i
;
if
(
__put_user
(
fb
->
emulations
[
0
],
&
fba
->
real_type
)
||
__put_user
(
0
,
&
fba
->
owner
)
||
__copy_to_user
(
&
fba
->
fbtype
,
&
fb
->
type
,
sizeof
(
struct
fbtype
))
||
__put_user
(
0
,
&
fba
->
sattr
.
flags
)
||
__put_user
(
fb
->
type
.
fb_type
,
&
fba
->
sattr
.
emu_type
)
||
__put_user
(
-
1
,
&
fba
->
sattr
.
dev_specific
[
0
]))
return
-
EFAULT
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
if
(
put_user
(
fb
->
emulations
[
i
],
&
fba
->
emu_types
[
i
]))
return
-
EFAULT
;
}
break
;
}
case
FBIOSATTR
:
i
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
struct
fbsattr
));
if
(
i
)
return
i
;
return
-
EINVAL
;
case
FBIOSVIDEO
:
if
(
fb
->
consolecnt
)
{
lastconsole
=
info
->
display_fg
->
vc_num
;
if
(
vt_cons
[
lastconsole
]
->
vc_mode
==
KD_TEXT
)
break
;
}
if
(
get_user
(
i
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
i
){
if
(
!
fb
->
blanked
||
!
fb
->
unblank
)
break
;
if
(
fb
->
consolecnt
||
(
fb
->
open
&&
fb
->
mmaped
))
(
*
fb
->
unblank
)(
fb
);
fb
->
blanked
=
0
;
}
else
{
if
(
fb
->
blanked
||
!
fb
->
blank
)
break
;
(
*
fb
->
blank
)(
fb
);
fb
->
blanked
=
1
;
}
break
;
case
FBIOGVIDEO
:
if
(
put_user
(
fb
->
blanked
,
(
int
*
)
arg
))
return
-
EFAULT
;
break
;
case
FBIOGETCMAP_SPARC
:
{
char
*
rp
,
*
gp
,
*
bp
;
int
end
,
count
,
index
;
struct
fbcmap
*
cmap
;
if
(
!
fb
->
loadcmap
)
return
-
EINVAL
;
i
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
struct
fbcmap
));
if
(
i
)
return
i
;
cmap
=
(
struct
fbcmap
*
)
arg
;
if
(
__get_user
(
count
,
&
cmap
->
count
)
||
__get_user
(
index
,
&
cmap
->
index
))
return
-
EFAULT
;
if
((
index
<
0
)
||
(
index
>
255
))
return
-
EINVAL
;
if
(
index
+
count
>
256
)
count
=
256
-
index
;
if
(
__get_user
(
rp
,
&
cmap
->
red
)
||
__get_user
(
gp
,
&
cmap
->
green
)
||
__get_user
(
bp
,
&
cmap
->
blue
))
return
-
EFAULT
;
if
(
verify_area
(
VERIFY_WRITE
,
rp
,
count
))
return
-
EFAULT
;
if
(
verify_area
(
VERIFY_WRITE
,
gp
,
count
))
return
-
EFAULT
;
if
(
verify_area
(
VERIFY_WRITE
,
bp
,
count
))
return
-
EFAULT
;
end
=
index
+
count
;
for
(
i
=
index
;
i
<
end
;
i
++
){
if
(
__put_user
(
fb
->
color_map
CM
(
i
,
0
),
rp
)
||
__put_user
(
fb
->
color_map
CM
(
i
,
1
),
gp
)
||
__put_user
(
fb
->
color_map
CM
(
i
,
2
),
bp
))
return
-
EFAULT
;
rp
++
;
gp
++
;
bp
++
;
}
(
*
fb
->
loadcmap
)(
fb
,
NULL
,
index
,
count
);
break
;
}
case
FBIOPUTCMAP_SPARC
:
{
/* load color map entries */
char
*
rp
,
*
gp
,
*
bp
;
int
end
,
count
,
index
;
struct
fbcmap
*
cmap
;
if
(
!
fb
->
loadcmap
||
!
fb
->
color_map
)
return
-
EINVAL
;
i
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
struct
fbcmap
));
if
(
i
)
return
i
;
cmap
=
(
struct
fbcmap
*
)
arg
;
if
(
__get_user
(
count
,
&
cmap
->
count
)
||
__get_user
(
index
,
&
cmap
->
index
))
return
-
EFAULT
;
if
((
index
<
0
)
||
(
index
>
255
))
return
-
EINVAL
;
if
(
index
+
count
>
256
)
count
=
256
-
index
;
if
(
__get_user
(
rp
,
&
cmap
->
red
)
||
__get_user
(
gp
,
&
cmap
->
green
)
||
__get_user
(
bp
,
&
cmap
->
blue
))
return
-
EFAULT
;
if
(
verify_area
(
VERIFY_READ
,
rp
,
count
))
return
-
EFAULT
;
if
(
verify_area
(
VERIFY_READ
,
gp
,
count
))
return
-
EFAULT
;
if
(
verify_area
(
VERIFY_READ
,
bp
,
count
))
return
-
EFAULT
;
end
=
index
+
count
;
for
(
i
=
index
;
i
<
end
;
i
++
){
if
(
__get_user
(
fb
->
color_map
CM
(
i
,
0
),
rp
))
return
-
EFAULT
;
if
(
__get_user
(
fb
->
color_map
CM
(
i
,
1
),
gp
))
return
-
EFAULT
;
if
(
__get_user
(
fb
->
color_map
CM
(
i
,
2
),
bp
))
return
-
EFAULT
;
rp
++
;
gp
++
;
bp
++
;
}
(
*
fb
->
loadcmap
)(
fb
,
NULL
,
index
,
count
);
break
;
}
case
FBIOGCURMAX
:
{
struct
fbcurpos
*
p
=
(
struct
fbcurpos
*
)
arg
;
if
(
!
fb
->
setcursor
)
return
-
EINVAL
;
if
(
verify_area
(
VERIFY_WRITE
,
p
,
sizeof
(
struct
fbcurpos
)))
return
-
EFAULT
;
if
(
__put_user
(
fb
->
cursor
.
hwsize
.
fbx
,
&
p
->
fbx
)
||
__put_user
(
fb
->
cursor
.
hwsize
.
fby
,
&
p
->
fby
))
return
-
EFAULT
;
break
;
}
case
FBIOSCURSOR
:
if
(
!
fb
->
setcursor
)
return
-
EINVAL
;
if
(
fb
->
consolecnt
)
{
lastconsole
=
info
->
display_fg
->
vc_num
;
if
(
vt_cons
[
lastconsole
]
->
vc_mode
==
KD_TEXT
)
return
-
EINVAL
;
/* Don't let graphics programs hide our nice text cursor */
fb
->
cursor
.
mode
=
CURSOR_SHAPE
;
/* Forget state of our text cursor */
}
return
sbus_hw_scursor
((
struct
fbcursor
*
)
arg
,
fb
);
case
FBIOSCURPOS
:
if
(
!
fb
->
setcursor
)
return
-
EINVAL
;
/* Don't let graphics programs move our nice text cursor */
if
(
fb
->
consolecnt
)
{
lastconsole
=
info
->
display_fg
->
vc_num
;
if
(
vt_cons
[
lastconsole
]
->
vc_mode
==
KD_TEXT
)
return
-
EINVAL
;
/* Don't let graphics programs move our nice text cursor */
}
if
(
copy_from_user
(
&
fb
->
cursor
.
cpos
,
(
void
*
)
arg
,
sizeof
(
struct
fbcurpos
)))
return
-
EFAULT
;
(
*
fb
->
setcursor
)
(
fb
);
break
;
default:
if
(
fb
->
ioctl
)
return
fb
->
ioctl
(
fb
,
cmd
,
arg
);
return
-
EINVAL
;
}
return
0
;
}
/*
* Setup: parse used options
*/
int
__init
sbusfb_setup
(
char
*
options
)
{
char
*
p
;
for
(
p
=
options
;;)
{
if
(
!
strncmp
(
p
,
"nomargins"
,
9
))
{
defx_margin
=
0
;
defy_margin
=
0
;
}
else
if
(
!
strncmp
(
p
,
"margins="
,
8
))
{
int
i
,
j
;
char
*
q
;
i
=
simple_strtoul
(
p
+
8
,
&
q
,
10
);
if
(
i
>=
0
&&
*
q
==
'x'
)
{
j
=
simple_strtoul
(
q
+
1
,
&
q
,
10
);
if
(
j
>=
0
&&
(
*
q
==
' '
||
!*
q
))
{
defx_margin
=
i
;
defy_margin
=
j
;
}
}
}
else
if
(
!
strncmp
(
p
,
"font="
,
5
))
{
int
i
;
for
(
i
=
0
;
i
<
sizeof
(
fontname
)
-
1
;
i
++
)
if
(
p
[
i
+
5
]
==
' '
||
!
p
[
i
+
5
])
break
;
memcpy
(
fontname
,
p
+
5
,
i
);
fontname
[
i
]
=
0
;
}
else
if
(
!
strncmp
(
p
,
"noblink"
,
7
))
curblink
=
0
;
while
(
*
p
&&
*
p
!=
' '
&&
*
p
!=
','
)
p
++
;
if
(
*
p
!=
','
)
break
;
p
++
;
}
return
0
;
}
static
int
sbusfbcon_switch
(
int
con
,
struct
fb_info
*
info
)
{
int
x_margin
,
y_margin
;
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
int
lastconsole
;
/* Do we have to save the colormap? */
if
(
fb_display
[
info
->
currcon
].
cmap
.
len
)
fb_get_cmap
(
&
fb_display
[
info
->
currcon
].
cmap
,
1
,
sbusfb_getcolreg
,
info
);
if
(
info
->
display_fg
)
{
lastconsole
=
info
->
display_fg
->
vc_num
;
if
(
lastconsole
!=
con
&&
(
fontwidth
(
&
fb_display
[
lastconsole
])
!=
fontwidth
(
&
fb_display
[
con
])
||
fontheight
(
&
fb_display
[
lastconsole
])
!=
fontheight
(
&
fb_display
[
con
])))
fb
->
cursor
.
mode
|=
CURSOR_SHAPE
;
}
x_margin
=
(
fb_display
[
con
].
var
.
xres_virtual
-
fb_display
[
con
].
var
.
xres
)
/
2
;
y_margin
=
(
fb_display
[
con
].
var
.
yres_virtual
-
fb_display
[
con
].
var
.
yres
)
/
2
;
if
(
fb
->
margins
)
fb
->
margins
(
fb
,
&
fb_display
[
con
],
x_margin
,
y_margin
);
if
(
fb
->
graphmode
||
fb
->
x_margin
!=
x_margin
||
fb
->
y_margin
!=
y_margin
)
{
fb
->
x_margin
=
x_margin
;
fb
->
y_margin
=
y_margin
;
sbusfb_clear_margin
(
&
fb_display
[
con
],
0
);
}
info
->
currcon
=
con
;
/* Install new colormap */
do_install_cmap
(
con
,
info
);
return
0
;
}
/*
* Update the `var' structure (called by fbcon.c)
*/
static
int
sbusfbcon_updatevar
(
int
con
,
struct
fb_info
*
info
)
{
/* Nothing */
return
0
;
}
/*
* Blank the display.
*/
static
int
sbusfb_blank
(
int
blank
,
struct
fb_info
*
info
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
if
(
blank
&&
fb
->
blank
)
return
fb
->
blank
(
fb
);
else
if
(
!
blank
&&
fb
->
unblank
)
return
fb
->
unblank
(
fb
);
return
0
;
}
/*
* Read a single color register and split it into
* colors/transparent. Return != 0 for invalid regno.
*/
static
int
sbusfb_getcolreg
(
u_int
regno
,
u_int
*
red
,
u_int
*
green
,
u_int
*
blue
,
u_int
*
transp
,
struct
fb_info
*
info
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
if
(
!
fb
->
color_map
||
regno
>
255
)
return
1
;
*
red
=
(
fb
->
color_map
CM
(
regno
,
0
)
<<
8
)
|
fb
->
color_map
CM
(
regno
,
0
);
*
green
=
(
fb
->
color_map
CM
(
regno
,
1
)
<<
8
)
|
fb
->
color_map
CM
(
regno
,
1
);
*
blue
=
(
fb
->
color_map
CM
(
regno
,
2
)
<<
8
)
|
fb
->
color_map
CM
(
regno
,
2
);
*
transp
=
0
;
return
0
;
}
/*
* Set a single color register. The values supplied are already
* rounded down to the hardware's capabilities (according to the
* entries in the var structure). Return != 0 for invalid regno.
*/
static
int
sbusfb_setcolreg
(
u_int
regno
,
u_int
red
,
u_int
green
,
u_int
blue
,
u_int
transp
,
struct
fb_info
*
info
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
if
(
!
fb
->
color_map
||
regno
>
255
)
return
1
;
red
>>=
8
;
green
>>=
8
;
blue
>>=
8
;
fb
->
color_map
CM
(
regno
,
0
)
=
red
;
fb
->
color_map
CM
(
regno
,
1
)
=
green
;
fb
->
color_map
CM
(
regno
,
2
)
=
blue
;
return
0
;
}
static
int
sbusfb_set_font
(
struct
display
*
p
,
int
width
,
int
height
)
{
int
margin
;
int
w
=
p
->
var
.
xres_virtual
,
h
=
p
->
var
.
yres_virtual
;
int
depth
=
p
->
var
.
bits_per_pixel
;
struct
fb_info_sbusfb
*
fb
=
sbusfbinfod
(
p
);
int
x_margin
,
y_margin
;
if
(
depth
>
8
)
depth
=
8
;
x_margin
=
0
;
y_margin
=
0
;
if
(
defx_margin
<
0
||
defy_margin
<
0
)
{
for
(
margin
=
0
;
def_margins
[
margin
].
depth
;
margin
++
)
if
(
w
==
def_margins
[
margin
].
xres
&&
h
==
def_margins
[
margin
].
yres
&&
depth
==
def_margins
[
margin
].
depth
)
{
x_margin
=
def_margins
[
margin
].
x_margin
;
y_margin
=
def_margins
[
margin
].
y_margin
;
break
;
}
}
else
{
x_margin
=
defx_margin
;
y_margin
=
defy_margin
;
}
x_margin
+=
((
w
-
2
*
x_margin
)
%
width
)
/
2
;
y_margin
+=
((
h
-
2
*
y_margin
)
%
height
)
/
2
;
p
->
var
.
xres
=
w
-
2
*
x_margin
;
p
->
var
.
yres
=
h
-
2
*
y_margin
;
fb
->
cursor
.
mode
|=
CURSOR_SHAPE
;
if
(
fb
->
margins
)
fb
->
margins
(
fb
,
p
,
x_margin
,
y_margin
);
if
(
fb
->
x_margin
!=
x_margin
||
fb
->
y_margin
!=
y_margin
)
{
fb
->
x_margin
=
x_margin
;
fb
->
y_margin
=
y_margin
;
sbusfb_clear_margin
(
p
,
0
);
}
return
1
;
}
void
sbusfb_palette
(
int
enter
)
{
int
i
;
struct
display
*
p
;
for
(
i
=
0
;
i
<
MAX_NR_CONSOLES
;
i
++
)
{
p
=
&
fb_display
[
i
];
if
(
p
->
dispsw
&&
p
->
dispsw
->
setup
==
sbusfb_disp_setup
&&
p
->
fb_info
->
display_fg
&&
p
->
fb_info
->
display_fg
->
vc_num
==
i
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfod
(
p
);
if
(
fb
->
restore_palette
)
{
if
(
enter
)
fb
->
restore_palette
(
fb
);
else
if
(
vt_cons
[
i
]
->
vc_mode
!=
KD_GRAPHICS
)
vc_cons
[
i
].
d
->
vc_sw
->
con_set_palette
(
vc_cons
[
i
].
d
,
color_table
);
}
}
}
}
/*
* Initialisation
*/
extern
void
(
*
prom_palette
)(
int
);
static
void
__init
sbusfb_init_fb
(
int
node
,
int
parent
,
int
fbtype
,
struct
sbus_dev
*
sbdp
)
{
struct
fb_fix_screeninfo
*
fix
;
struct
fb_var_screeninfo
*
var
;
struct
display
*
disp
;
struct
fb_info_sbusfb
*
fb
;
struct
fbtype
*
type
;
int
linebytes
,
w
,
h
,
depth
;
char
*
p
=
NULL
;
int
margin
;
fb
=
kmalloc
(
sizeof
(
struct
fb_info_sbusfb
),
GFP_ATOMIC
);
if
(
!
fb
)
{
prom_printf
(
"Could not allocate sbusfb structure
\n
"
);
return
;
}
if
(
!
prom_palette
)
prom_palette
=
sbusfb_palette
;
memset
(
fb
,
0
,
sizeof
(
struct
fb_info_sbusfb
));
fix
=
&
fb
->
info
.
fix
;
var
=
&
fb
->
info
.
var
;
disp
=
&
fb
->
disp
;
type
=
&
fb
->
type
;
spin_lock_init
(
&
fb
->
lock
);
fb
->
prom_node
=
node
;
fb
->
prom_parent
=
parent
;
fb
->
sbdp
=
sbdp
;
if
(
sbdp
)
fb
->
iospace
=
sbdp
->
reg_addrs
[
0
].
which_io
;
type
->
fb_type
=
fbtype
;
memset
(
&
fb
->
emulations
,
0xff
,
sizeof
(
fb
->
emulations
));
fb
->
emulations
[
0
]
=
fbtype
;
#ifdef CONFIG_SPARC32
fb
->
info
.
screen_base
=
(
unsigned
char
*
)
prom_getintdefault
(
node
,
"address"
,
0
);
#endif
type
->
fb_height
=
h
=
prom_getintdefault
(
node
,
"height"
,
900
);
type
->
fb_width
=
w
=
prom_getintdefault
(
node
,
"width"
,
1152
);
sizechange:
type
->
fb_depth
=
depth
=
(
fbtype
==
FBTYPE_SUN2BW
)
?
1
:
8
;
linebytes
=
prom_getintdefault
(
node
,
"linebytes"
,
w
*
depth
/
8
);
type
->
fb_size
=
PAGE_ALIGN
((
linebytes
)
*
h
);
if
(
defx_margin
<
0
||
defy_margin
<
0
)
{
for
(
margin
=
0
;
def_margins
[
margin
].
depth
;
margin
++
)
if
(
w
==
def_margins
[
margin
].
xres
&&
h
==
def_margins
[
margin
].
yres
&&
depth
==
def_margins
[
margin
].
depth
)
{
fb
->
x_margin
=
def_margins
[
margin
].
x_margin
;
fb
->
y_margin
=
def_margins
[
margin
].
y_margin
;
break
;
}
}
else
{
fb
->
x_margin
=
defx_margin
;
fb
->
y_margin
=
defy_margin
;
}
fb
->
x_margin
+=
((
w
-
2
*
fb
->
x_margin
)
&
7
)
/
2
;
fb
->
y_margin
+=
((
h
-
2
*
fb
->
y_margin
)
&
15
)
/
2
;
var
->
xres_virtual
=
w
;
var
->
yres_virtual
=
h
;
var
->
xres
=
w
-
2
*
fb
->
x_margin
;
var
->
yres
=
h
-
2
*
fb
->
y_margin
;
var
->
bits_per_pixel
=
depth
;
var
->
height
=
var
->
width
=
-
1
;
var
->
pixclock
=
10000
;
var
->
vmode
=
FB_VMODE_NONINTERLACED
;
var
->
red
.
length
=
var
->
green
.
length
=
var
->
blue
.
length
=
8
;
fix
->
line_length
=
linebytes
;
fix
->
smem_len
=
type
->
fb_size
;
fix
->
type
=
FB_TYPE_PACKED_PIXELS
;
fix
->
visual
=
FB_VISUAL_PSEUDOCOLOR
;
fb
->
info
.
node
=
NODEV
;
fb
->
info
.
fbops
=
&
sbusfb_ops
;
fb
->
info
.
disp
=
disp
;
fb
->
info
.
currcon
=
-
1
;
strcpy
(
fb
->
info
.
fontname
,
fontname
);
fb
->
info
.
changevar
=
NULL
;
fb
->
info
.
switch_con
=
&
sbusfbcon_switch
;
fb
->
info
.
updatevar
=
&
sbusfbcon_updatevar
;
fb
->
info
.
flags
=
FBINFO_FLAG_DEFAULT
;
fb
->
cursor
.
hwsize
.
fbx
=
32
;
fb
->
cursor
.
hwsize
.
fby
=
32
;
if
(
depth
>
1
&&
!
fb
->
color_map
)
fb
->
color_map
=
kmalloc
(
256
*
3
,
GFP_ATOMIC
);
switch
(
fbtype
)
{
#ifdef CONFIG_FB_CREATOR
case
FBTYPE_CREATOR
:
p
=
creatorfb_init
(
fb
);
break
;
#endif
#ifdef CONFIG_FB_CGSIX
case
FBTYPE_SUNFAST_COLOR
:
p
=
cgsixfb_init
(
fb
);
break
;
#endif
#ifdef CONFIG_FB_CGTHREE
case
FBTYPE_SUN3COLOR
:
p
=
cgthreefb_init
(
fb
);
break
;
#endif
#ifdef CONFIG_FB_TCX
case
FBTYPE_TCXCOLOR
:
p
=
tcxfb_init
(
fb
);
break
;
#endif
#ifdef CONFIG_FB_LEO
case
FBTYPE_SUNLEO
:
p
=
leofb_init
(
fb
);
break
;
#endif
#ifdef CONFIG_FB_BWTWO
case
FBTYPE_SUN2BW
:
p
=
bwtwofb_init
(
fb
);
break
;
#endif
#ifdef CONFIG_FB_CGFOURTEEN
case
FBTYPE_MDICOLOR
:
p
=
cgfourteenfb_init
(
fb
);
break
;
#endif
#ifdef CONFIG_FB_P9100
case
FBTYPE_P9100COLOR
:
/* Temporary crock. For now we are a cg3 */
p
=
p9100fb_init
(
fb
);
type
->
fb_type
=
FBTYPE_SUN3COLOR
;
break
;
#endif
}
if
(
!
p
)
{
if
(
fb
->
color_map
)
kfree
(
fb
->
color_map
);
kfree
(
fb
);
return
;
}
if
(
p
==
SBUSFBINIT_SIZECHANGE
)
goto
sizechange
;
disp
->
dispsw
=
&
fb
->
dispsw
;
if
(
fb
->
setcursor
)
{
fb
->
dispsw
.
cursor
=
sbusfb_cursor
;
if
(
curblink
)
{
fb
->
cursor
.
blink_rate
=
DEFAULT_CURSOR_BLINK_RATE
;
init_timer
(
&
fb
->
cursor
.
timer
);
fb
->
cursor
.
timer
.
expires
=
jiffies
+
fb
->
cursor
.
blink_rate
;
fb
->
cursor
.
timer
.
data
=
(
unsigned
long
)
fb
;
fb
->
cursor
.
timer
.
function
=
sbusfb_cursor_timer_handler
;
add_timer
(
&
fb
->
cursor
.
timer
);
}
}
fb
->
cursor
.
mode
=
CURSOR_SHAPE
;
fb
->
dispsw
.
set_font
=
sbusfb_set_font
;
fb
->
setup
=
fb
->
dispsw
.
setup
;
fb
->
dispsw
.
setup
=
sbusfb_disp_setup
;
fb
->
dispsw
.
clear_margins
=
NULL
;
disp
->
var
=
*
var
;
if
(
fb
->
blank
)
disp
->
can_soft_blank
=
1
;
sbusfb_set_var
(
var
,
-
1
,
&
fb
->
info
);
if
(
register_framebuffer
(
&
fb
->
info
)
<
0
)
{
if
(
fb
->
color_map
)
kfree
(
fb
->
color_map
);
kfree
(
fb
);
return
;
}
printk
(
KERN_INFO
"fb%d: %s
\n
"
,
minor
(
fb
->
info
.
node
),
p
);
}
static
inline
int
known_card
(
char
*
name
)
{
char
*
p
;
for
(
p
=
name
;
*
p
&&
*
p
!=
','
;
p
++
);
if
(
*
p
==
','
)
name
=
p
+
1
;
if
(
!
strcmp
(
name
,
"cgsix"
)
||
!
strcmp
(
name
,
"cgthree+"
))
return
FBTYPE_SUNFAST_COLOR
;
if
(
!
strcmp
(
name
,
"cgthree"
)
||
!
strcmp
(
name
,
"cgRDI"
))
return
FBTYPE_SUN3COLOR
;
if
(
!
strcmp
(
name
,
"cgfourteen"
))
return
FBTYPE_MDICOLOR
;
if
(
!
strcmp
(
name
,
"leo"
))
return
FBTYPE_SUNLEO
;
if
(
!
strcmp
(
name
,
"bwtwo"
))
return
FBTYPE_SUN2BW
;
if
(
!
strcmp
(
name
,
"tcx"
))
return
FBTYPE_TCXCOLOR
;
if
(
!
strcmp
(
name
,
"p9100"
))
return
FBTYPE_P9100COLOR
;
return
FBTYPE_NOTYPE
;
}
#ifdef CONFIG_FB_CREATOR
static
void
creator_fb_scan_siblings
(
int
root
)
{
int
node
,
child
;
child
=
prom_getchild
(
root
);
for
(
node
=
prom_searchsiblings
(
child
,
"SUNW,ffb"
);
node
;
node
=
prom_searchsiblings
(
prom_getsibling
(
node
),
"SUNW,ffb"
))
sbusfb_init_fb
(
node
,
root
,
FBTYPE_CREATOR
,
NULL
);
for
(
node
=
prom_searchsiblings
(
child
,
"SUNW,afb"
);
node
;
node
=
prom_searchsiblings
(
prom_getsibling
(
node
),
"SUNW,afb"
))
sbusfb_init_fb
(
node
,
root
,
FBTYPE_CREATOR
,
NULL
);
}
static
void
creator_fb_scan
(
void
)
{
int
root
;
creator_fb_scan_siblings
(
prom_root_node
);
root
=
prom_getchild
(
prom_root_node
);
for
(
root
=
prom_searchsiblings
(
root
,
"upa"
);
root
;
root
=
prom_searchsiblings
(
prom_getsibling
(
root
),
"upa"
))
creator_fb_scan_siblings
(
root
);
}
#endif
int
__init
sbusfb_init
(
void
)
{
int
type
;
struct
sbus_dev
*
sbdp
;
struct
sbus_bus
*
sbus
;
char
prom_name
[
40
];
extern
int
con_is_present
(
void
);
if
(
!
con_is_present
())
return
-
ENXIO
;
#ifdef CONFIG_FB_CREATOR
creator_fb_scan
();
#endif
#ifdef CONFIG_SUN4
sbusfb_init_fb
(
0
,
0
,
FBTYPE_SUN2BW
,
NULL
);
#endif
#if defined(CONFIG_FB_CGFOURTEEN) && !defined(__sparc_v9__)
{
int
root
,
node
;
root
=
prom_getchild
(
prom_root_node
);
root
=
prom_searchsiblings
(
root
,
"obio"
);
if
(
root
&&
(
node
=
prom_searchsiblings
(
prom_getchild
(
root
),
"cgfourteen"
)))
{
sbusfb_init_fb
(
node
,
root
,
FBTYPE_MDICOLOR
,
NULL
);
}
}
#endif
if
(
sbus_root
==
NULL
)
return
0
;
for_all_sbusdev
(
sbdp
,
sbus
)
{
type
=
known_card
(
sbdp
->
prom_name
);
if
(
type
==
FBTYPE_NOTYPE
)
continue
;
if
(
prom_getproperty
(
sbdp
->
prom_node
,
"emulation"
,
prom_name
,
sizeof
(
prom_name
))
>
0
)
{
type
=
known_card
(
prom_name
);
if
(
type
==
FBTYPE_NOTYPE
)
type
=
known_card
(
sbdp
->
prom_name
);
}
sbusfb_init_fb
(
sbdp
->
prom_node
,
sbdp
->
bus
->
prom_node
,
type
,
sbdp
);
}
return
0
;
}
MODULE_LICENSE
(
"GPL"
);
drivers/video/sbuslib.c
0 → 100644
View file @
250883f3
/* sbuslib.c: Helper library for SBUS framebuffer drivers.
*
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
#include <asm/oplib.h>
#include "sbuslib.h"
void
sbusfb_fill_var
(
struct
fb_var_screeninfo
*
var
,
int
prom_node
,
int
bpp
)
{
memset
(
var
,
0
,
sizeof
(
*
var
));
var
->
xres
=
prom_getintdefault
(
prom_node
,
"width"
,
1152
);
var
->
yres
=
prom_getintdefault
(
prom_node
,
"height"
,
900
);
var
->
xres_virtual
=
var
->
xres
;
var
->
yres_virtual
=
var
->
yres
;
var
->
bits_per_pixel
=
bpp
;
}
EXPORT_SYMBOL
(
sbusfb_fill_var
);
static
unsigned
long
sbusfb_mmapsize
(
long
size
,
unsigned
long
fbsize
)
{
if
(
size
==
SBUS_MMAP_EMPTY
)
return
0
;
if
(
size
>=
0
)
return
size
;
return
fbsize
*
(
-
size
);
}
int
sbusfb_mmap_helper
(
struct
sbus_mmap_map
*
map
,
unsigned
long
physbase
,
unsigned
long
fbsize
,
unsigned
long
iospace
,
struct
vm_area_struct
*
vma
)
{
unsigned
int
size
,
page
,
r
,
map_size
;
unsigned
long
map_offset
=
0
;
unsigned
long
off
;
int
i
;
size
=
vma
->
vm_end
-
vma
->
vm_start
;
if
(
vma
->
vm_pgoff
>
(
~
0UL
>>
PAGE_SHIFT
))
return
-
EINVAL
;
off
=
vma
->
vm_pgoff
<<
PAGE_SHIFT
;
/* To stop the swapper from even considering these pages */
vma
->
vm_flags
|=
(
VM_SHM
|
VM_IO
|
VM_LOCKED
);
/* Each page, see which map applies */
for
(
page
=
0
;
page
<
size
;
){
map_size
=
0
;
for
(
i
=
0
;
map
[
i
].
size
;
i
++
)
if
(
map
[
i
].
voff
==
off
+
page
)
{
map_size
=
sbusfb_mmapsize
(
map
[
i
].
size
,
fbsize
);
#ifdef __sparc_v9__
#define POFF_MASK (PAGE_MASK|0x1UL)
#else
#define POFF_MASK (PAGE_MASK)
#endif
map_offset
=
(
physbase
+
map
[
i
].
poff
)
&
POFF_MASK
;
break
;
}
if
(
!
map_size
){
page
+=
PAGE_SIZE
;
continue
;
}
if
(
page
+
map_size
>
size
)
map_size
=
size
-
page
;
r
=
io_remap_page_range
(
vma
,
vma
->
vm_start
+
page
,
map_offset
,
map_size
,
vma
->
vm_page_prot
,
iospace
);
if
(
r
)
return
-
EAGAIN
;
page
+=
map_size
;
}
return
0
;
}
drivers/video/sbuslib.h
0 → 100644
View file @
250883f3
/* sbuslib.h: SBUS fb helper library interfaces */
#ifndef _SBUSLIB_H
#define _SBUSLIB_H
struct
sbus_mmap_map
{
unsigned
long
voff
;
unsigned
long
poff
;
unsigned
long
size
;
};
#define SBUS_MMAP_FBSIZE(n) (-n)
#define SBUS_MMAP_EMPTY 0x80000000
extern
void
sbusfb_fill_var
(
struct
fb_var_screeninfo
*
var
,
int
prom_node
,
int
bpp
);
struct
vm_area_struct
;
extern
int
sbusfb_mmap_helper
(
struct
sbus_mmap_map
*
map
,
unsigned
long
physbase
,
unsigned
long
fbsize
,
unsigned
long
iospace
,
struct
vm_area_struct
*
vma
);
#endif
/* _SBUSLIB_H */
include/video/sbusfb.h
deleted
100644 → 0
View file @
743b21c5
#include <linux/timer.h>
#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/fbio.h>
#include <video/fbcon.h>
struct
bt_regs
{
volatile
unsigned
int
addr
;
/* address register */
volatile
unsigned
int
color_map
;
/* color map */
volatile
unsigned
int
control
;
/* control register */
volatile
unsigned
int
cursor
;
/* cursor map register */
};
struct
fb_info_creator
{
struct
ffb_fbc
*
fbc
;
struct
ffb_dac
*
dac
;
int
xy_margin
;
int
fifo_cache
;
u64
yx_margin
;
int
fg_cache
;
int
bg_cache
;
int
dac_rev
;
};
struct
fb_info_cgsix
{
struct
bt_regs
*
bt
;
struct
cg6_fbc
*
fbc
;
struct
cg6_thc
*
thc
;
struct
cg6_tec
*
tec
;
volatile
u32
*
fhc
;
};
struct
fb_info_bwtwo
{
struct
bw2_regs
*
regs
;
};
struct
fb_info_cgthree
{
struct
cg3_regs
*
regs
;
};
struct
fb_info_tcx
{
struct
bt_regs
*
bt
;
struct
tcx_thc
*
thc
;
struct
tcx_tec
*
tec
;
u32
*
cplane
;
};
struct
fb_info_leo
{
struct
leo_lx_krn
*
lx_krn
;
struct
leo_lc_ss0_usr
*
lc_ss0_usr
;
struct
leo_ld_ss0
*
ld_ss0
;
struct
leo_ld_ss1
*
ld_ss1
;
struct
leo_cursor
*
cursor
;
unsigned
int
extent
;
};
struct
fb_info_cgfourteen
{
struct
cg14_regs
*
regs
;
struct
cg14_cursor
*
cursor
;
struct
cg14_clut
*
clut
;
int
ramsize
;
int
mode
;
};
struct
fb_info_p9100
{
struct
p9100_ctrl
*
ctrl
;
volatile
u32
*
fbmem
;
};
struct
cg_cursor
{
char
enable
;
/* cursor is enabled */
char
mode
;
/* cursor mode */
struct
fbcurpos
cpos
;
/* position */
struct
fbcurpos
chot
;
/* hot-spot */
struct
fbcurpos
size
;
/* size of mask & image fields */
struct
fbcurpos
hwsize
;
/* hw max size */
int
bits
[
2
][
128
];
/* space for mask & image bits */
char
color
[
6
];
/* cursor colors */
struct
timer_list
timer
;
/* cursor timer */
int
blink_rate
;
/* cursor blink rate */
};
struct
sbus_mmap_map
{
unsigned
long
voff
;
unsigned
long
poff
;
unsigned
long
size
;
};
#define SBUS_MMAP_FBSIZE(n) (-n)
#define SBUS_MMAP_EMPTY 0x80000000
struct
fb_info_sbusfb
{
struct
fb_info
info
;
struct
display
disp
;
struct
display_switch
dispsw
;
struct
fbtype
type
;
struct
sbus_dev
*
sbdp
;
spinlock_t
lock
;
int
prom_node
,
prom_parent
;
union
{
struct
fb_info_creator
ffb
;
struct
fb_info_cgsix
cg6
;
struct
fb_info_bwtwo
bw2
;
struct
fb_info_cgthree
cg3
;
struct
fb_info_tcx
tcx
;
struct
fb_info_leo
leo
;
struct
fb_info_cgfourteen
cg14
;
struct
fb_info_p9100
p9100
;
}
s
;
unsigned
char
*
color_map
;
struct
cg_cursor
cursor
;
unsigned
char
open
;
unsigned
char
mmaped
;
unsigned
char
blanked
;
int
x_margin
;
int
y_margin
;
int
vtconsole
;
int
consolecnt
;
int
graphmode
;
int
emulations
[
4
];
struct
sbus_mmap_map
*
mmap_map
;
unsigned
long
physbase
;
int
iospace
;
/* Methods */
void
(
*
setup
)(
struct
display
*
);
void
(
*
setcursor
)(
struct
fb_info_sbusfb
*
);
void
(
*
setcurshape
)(
struct
fb_info_sbusfb
*
);
void
(
*
setcursormap
)(
struct
fb_info_sbusfb
*
,
unsigned
char
*
,
unsigned
char
*
,
unsigned
char
*
);
void
(
*
loadcmap
)(
struct
fb_info_sbusfb
*
,
struct
display
*
,
int
,
int
);
int
(
*
blank
)(
struct
fb_info_sbusfb
*
);
int
(
*
unblank
)(
struct
fb_info_sbusfb
*
);
void
(
*
margins
)(
struct
fb_info_sbusfb
*
,
struct
display
*
,
int
,
int
);
void
(
*
reset
)(
struct
fb_info_sbusfb
*
);
void
(
*
fill
)(
struct
fb_info_sbusfb
*
,
struct
display
*
,
int
,
int
,
unsigned
short
*
);
void
(
*
switch_from_graph
)(
struct
fb_info_sbusfb
*
);
void
(
*
restore_palette
)(
struct
fb_info_sbusfb
*
);
int
(
*
ioctl
)(
struct
fb_info_sbusfb
*
,
unsigned
int
,
unsigned
long
);
};
extern
char
*
creatorfb_init
(
struct
fb_info_sbusfb
*
);
extern
char
*
cgsixfb_init
(
struct
fb_info_sbusfb
*
);
extern
char
*
cgthreefb_init
(
struct
fb_info_sbusfb
*
);
extern
char
*
tcxfb_init
(
struct
fb_info_sbusfb
*
);
extern
char
*
leofb_init
(
struct
fb_info_sbusfb
*
);
extern
char
*
bwtwofb_init
(
struct
fb_info_sbusfb
*
);
extern
char
*
cgfourteenfb_init
(
struct
fb_info_sbusfb
*
);
extern
char
*
p9100fb_init
(
struct
fb_info_sbusfb
*
);
#define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info))
#define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info))
#define CM(i, j) [3*(i)+(j)]
#define SBUSFBINIT_SIZECHANGE ((char *)-1)
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