Enter fbcon - THE.UNIX.WORLD
Pubblicato da Konstantin Boldyshev il 02/2000
Livello intermedio

Introduzione

/* Questo articolo e' stato tratto dall'Assembly Programming Journal numero 7 */

::/ \::::::.
:/___\:::::::.
/|    \::::::::.
:|   _/\:::::::::.
:| _ |\ \::::::::::.
:::\_____\:::::::::::............................................THE.UNIX.WORLD

Iniziamo

Many of Linux users have heard something about fbcon. It is becoming more and more popular, mostly because of capability of getting graphics on usual terminal without X. How to use graphic capabilities of fbcon?
The /dev/fb# devices represent frame buffer devices; they allow the frame buffer of a video card to be read and written to by a user, and allow a programmer to access the video hardware [and, more importantly, the video memory] through ioctls and memory mapping.
The general approach to using fbcon is pretty simple:
1) open /dev/fb0
2) mmap /dev/fb0
3) .. do the thing .. (use pointer returned by mmap to access videomemory)
4) munmap /dev/fb0
5) close /dev/fb0
I've taken one of my old DOS intros made in tasm, and rewritten it for nasm and Linux/fbcon. At 408 bytes, This intro is the smallest implementation of linear transformation with recursion (AFAIK).
Leaves.asm runs for about a minute and a half (depends on machine), and is interruptible at any time with ^C. If everything is ok you should see two branches of green leaves, and kinda wind blowing on them. It MUST be run only in 640x480x256 mode (vga=0x301 in lilo.conf). You will see garbage or incorrect colors in other modes.
Warning! Intro assumes that everything is ok with the system (/dev/fb0 exists, can be opened and mmap()ed, correct video mode is set, and so on).
So, if you ain't root, check permissions on /dev/fb0 first, or you will not see anything.
The source is quite portable, you only need to implement putpixel() and initial-ization part for your OS. To get the basic idea across, here is the fbcon implementation in C:


//==========================================================================
// leaves.c : C implementation using /dev/fb0
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

typedef unsigned char byte;
typedef unsigned int word;
typedef float dword;

#define MaxX 640
#define MaxY 480
#define VMEM_SIZE MaxX*MaxY

#define xc MaxX/2
#define yc MaxY/2
#define xmin0 100
#define xmax0 -xmin0
#define ymin0 xmin0
#define ymax0 -ymin0

#define colornum 8

int h;
byte *p;

byte ColorTable[colornum] = { 0x00,0x00,0x02,0x00,0x00,0x02,0x0A,0x02 };
int color=0;

dword f=MaxY/(ymax0-ymin0)*3/2;
dword x1coef=MaxX-MaxY*4/9-yc;
dword y1coef=MaxY/4+xc;
dword x2coef=MaxY*4/9+yc;
dword x0=110;

dword a=0.7;
dword b=0.2;
dword c=0.5;
dword d=0.3;

void putpixel(word x,word y,byte color)
{
 *(p+y*MaxX+x) = color;
}

void leaves(dword x,dword y,byte n)
{
 word x1,y1;

 if (n>0)
 {
  y1=f*x+y1coef;

  putpixel(x1coef-f*y,y1,ColorTable[color]);
  putpixel(f*y+x2coef,y1,ColorTable[color]);

  if (++color>colornum-1) color=0;

  leaves(a*x+b*y, b*x-a*y, n-1);
  leaves(c*(x-x0)-d*y+x0,d*(x-x0)+c*y,n-1);

 }
}

int main(void)
{
 int i;

 p=mmap(0,VMEM_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,open("/dev/fb0",O_RDWR),0);

 for (i=0;i<VMEM_SIZE;i++) *(p+i) = 0;

 leaves(0,0,28);

 munmap(p,VMEM_SIZE);
 close(h);
}
//--------------------------------------------------------------------------EOF

Here is the asm source. It is quite short and self-explaining :) Well, actually the source is badly optimized for size, contains some Linux-specific tricks, and can be hard to understand. Please refer to the C source for areas that need clarification.
NOTE: The following source was taken from asmutils and requires asmutils macros (*.inc), available from http://linuxassembly.org; you can also download binary there (in samples archive)
To compile leaves.asm:


$ nasm -f elf leaves.asm
$ ld -s -o leaves leaves.o

;==========================================================================
;Copyright (C) 1999 Konstantin Boldyshev <[email protected]>
;
;leaves - fbcon intro in 408 bytes
;
;Ah, /if haven't guessed yet/ license is GPL, so enjoy! :)

%include "system.inc"

%assign SIZE_X 640
%assign SIZE_Y 480
%assign DEPTH 8
%assign VMEM_SIZE SIZE_X*SIZE_Y

%define MaxX 640.0
%define MaxY 480.0
%define xc MaxX/2
%define yc MaxY/2
%define xmin0 100.0
%define xmax0 -xmin0
%define ymin0 xmin0
%define ymax0 -ymin0

CODESEG
;al - color
putpixel:
push edx
lea edx,[ebx+ebx*4] ;computing offset..
shl edx,byte 7 ;multiply on 640
add edx,[esp+8]
mov [edx+esi],al ;write to frame buffer
pop edx
_return:
ret

; recursive function itself
leaves:
mov ecx,[esp+12]
test cl,cl
jz _return
mov [esp-13],cl
mov eax,[edi]
push ecx
sub esp,byte 8
mov edx,esp

fld dword [ebp+16] ;[f]
fld st0
fld st0
fmul dword [edx+16]
fadd dword [ebp+24] ;[y1coef]
fistp dword [edx]
mov ebx,[edx]
fmul dword [edx+20]
fsubr dword [ebp+20] ;[x1coef]
fistp dword [edx]
call putpixel
fmul dword [edx+20]
fadd dword [ebp+28] ;[x2coef]
fistp dword [edx]
call putpixel
inc edi
cmp edi,ColorEnd
jl .rec
sub edi,byte ColorEnd-ColorBegin

.rec:
fld dword [ebp+4] ;[b]
fld dword [ebp] ;[a]
fld st1
fld st1
fxch
fmul dword [edx+16]
fxch
fmul dword [edx+20]
fsubp st1
fstp dword [edx-8]

fmul dword [edx+16]
fxch
fmul dword [edx+20]
faddp st1
dec ecx
push ecx
sub esp,byte 8
fstp dword [esp]
call leaves ;esp+12
mov edx,esp
fld dword [ebp+12] ;[d]
fld dword [edx+28]
fld dword [ebp+8] ;[c]
fld dword [ebp+32] ;[x0]
fsub to st2
fld st3
fld st2
fxch
fmul st4
fxch
fmul dword [edx+32]
faddp st1
fstp dword [edx-8]

fxch
fmulp st2
fxch st2
fmul dword [edx+32]
fsubp st1
faddp st1
push ecx
sub esp,byte 8
fstp dword [esp]
call leaves
add esp,byte 12*2+8
pop ecx
.return:
ret

;------------------------------------- main()
START:
;prepare structure for mmap on the stack
mov edi,VMEM_SIZE
mov esi,esp
mov [esi-16],edi ;.len
mov [esi-12],byte PROT_READ|PROT_WRITE ;.prot
mov [esi-8],byte MAP_SHARED ;.flags
mov [esi],edx ;.offset

;init fb
mov ebp,Params
lea ebx,[ebp+0x2C] ;fb-Params
sys_open EMPTY,O_RDWR

test eax,eax ;have we opened file?
js exit

mov [esi-4],eax ;mm.fd
lea ebx,[esi-20]
sys_mmap

test eax,eax ;have we mmaped file?
js exit

mov esi,eax

;clear screen
mov ecx,edi
mov edi,esi
xor eax,eax
rep stosb

;leaves
lea edi,[ebp+0x24] ;ColorBegin-Params
push byte 28 ;recursion depth
push eax
push eax
call leaves

;close fb
sys_munmap esi,VMEM_SIZE
sys_close [mm.fd]

exit:
sys_exit

;----------------------------Parameters
Params:

a dd 0.7
b dd 0.2
c dd 0.5
d dd 0.3

f dd 0xc0400000 ;MaxY/(ymax0-ymin0)*3/2
x1coef dd 0x433b0000 ;MaxX-MaxY*4/9-yc
y1coef dd 0x43dc0000 ;MaxY/4+xc
x2coef dd 0x43e28000 ;MaxY*4/9+yc
x0 dd 112.0

ColorBegin:
db 0,0,2,0,0,2,10,2
ColorEnd:

fb db "/dev/fb0";,NULL

END
;===========================================================================EOF

Conclusioni

More information on the frame buffer device can be found in the Linux kernel documentation [ usually /usr/src/linux/Documentation ] files framebuffer.txt, internals.txt, matroxfb.txt, tgafb.txt, and vesafb.txt. The /dev/fbcon# ioctls are defined in /usr/include/linux/fb.h .
Enjoy the demo!