요즘 touch device 에 이어서 display module인 v4l2와 frame buffer 등의 업무를 담당하고 있다.
공부를 해 나아가며 찾은 자료들을 이곳에 keeping 하려 한다.
좋은 자료를 만들어 주신분께 먼저 감사를 드린다.
원문 : http://kelp.or.kr/korweblog/stories.php?story=02/11/09/8557035
== 시작하기에 앞서
이 글에 있는 모든 내용은 글쓴이가 가지고 있는 ATI mach 64(2MB) 그래픽 카드가 달려있고 RedHat 8.0이 설치된 PC(또는 Permedia2(8MB) 그래픽 카드가 달려 있는 RedHat 7.3이 설치된 PC)에서 제대로 동작하지만 이 글에 있는 모든 내용이 정확하다고 말씀 드릴 수 없습니다. 이 글에 있는 내용을 따라 했을 때 혹 생길 지 모르는 모든 문제에 대해서 글쓴이는 책임을 지지 않습니다. 글의 내용 중에 잘못된 내용이 있거나 질문할 것이 있으면 위쪽의 “holelee”를 누르고 메일을 보내기 바랍니다.
== 글을 쓴 동기
이곳 KELP 사이트 질문/답변 란에 가끔씩 올라오는 질문 중에 하나는 frame buffer 디바이스에 관련된 내용입니다. 이를 테면 StrongARM 보드에 LCD 드라이버를 다 올렸는데 그 LCD에 bmp와 같은 그림 파일을 읽어서 나타내고 싶은데 어떻게 하는지 모르겠다는 내용이죠. 그것에 대한 답변을 짧게 주고는 있으나 많은 사람들이 아직 잘 모를 것 같아서 정리해 보려고 합니다.
== frame buffer 란?
우선 모든 이야기에 앞서 Frame buffer가 무엇인지 알아야 하겠죠. Frame buffer란 linux 시스템에서 그래픽을 표현할 수 있는 하드웨어를 말합니다. 즉, PC라면 그래픽 카드, StrongARM 같으면 LCD controller를 frame buffer 장치라고 할 수 있습니다. 그 하드웨어를 user level application이 제어할 수 있도록 만들어진 device driver를 frame buffer driver라고 말할 수 있습니다. 그런데 마구 잡이로 만드는 device driver가 아니 application 작성자가 코딩을 할 수 있어야 하므로 어떠한 표준화된 interface를 가지고 있습니다. 사실 이 글의 내용은 그 interface를 배우는 것입니다.
(사실 frame buffer는 말 그대로 frame을 저장하고 있는 buffer를 의미합니다. Buffer가 무슨 뜻인지는 아실 테고, frame은 한 장의 그림을 나타낸다고 보시면 편합니다. 단지 여기서 말하는 frame은 LCD나 CRT등의 표시 장치의 화면에 출력될 그림입니다.)
== 글의 내용 및 구성
전체 글의 내용은 frame buffer 디바이스를 사용하여 화면에 이미지를 뿌리는 방법에 관한 것입니다. Frame buffer 디바이스 드라이버를 포팅하거나 하는 내용은 전혀 없습니다. 또한 모든 예제는 PC 기반의 linux system에서 수행할 수 있도록 작성되었습니다. 이곳 KELP 사이트가 embedded linux system을 주로 다루고 있지만, 특정 target(예를 들어 640x480x16bit LCD가 달려 있는 StrongARM 보드)에서 진행하지 않는 이유는 다음과 같습니다.
(1) PC 기반의 linux가 접하기 쉽다.
(2) 그런 보드를 가지고 있지 않다.
(3) 그런 target에서 글을 진행할 필요가 별로 없다.
(1)번과, (2)번은 쉽게 이해하겠죠. (3)에 대해서는 잠시 언급하도록 하겠습니다. 어짜피 우리는 linux라는 시스템에서 frame buffer 디바이스를 사용하는 프로그램을 작성합니다. 위에서 언급한대로 frame buffer driver는 어떤 표준화된 interface를 제공합니다. 따라서 어떤 linux 시스템에서 application을 작성하고 테스트하든지 큰 차이는 없습니다.
(사실 약간의 차이는 존재합니다. 지원하는 해상도나 픽셀당 비트수(bit per pixel) 등은 하드웨어 마다 다르죠. 하지만 현재 셋팅되어 있는 값을 읽어 올 수 있는 interface도 존재하고 지원하지 않는 해상도로 바꾸려고 했을 때 에러를 리턴한다거나 해서 어느 정도의 차이는 극복할 수 있습니다. 사실 이러한 차이는 모든 하드웨어에서도 마찬가지로 존재하죠. 예를 들어 Serial port가 9600bps까지 지원하는 하드웨어가 있을 수 있는 반면 그보다 빠른 속도로 동작할 수 있는 하드웨어도 존재하죠. 그렇다고 시리얼 프로그래밍의 방법이 바뀐다든지 하지 않는 것처럼 frame buffer driver 프로그래밍도 하드웨어마다 크게 바뀌지 않습니다.)
이번 글은 PC 기반의 linux 시스템에서 frame buffer device를 프로그래밍하기 위한 준비에 대한 글이고 다음 글부터 작성된 예제 소스코드를 살펴보고 직접 수행해 보는 형식으로 진행될 예정입니다.
== xdm을 끄기
PC linux 시스템이 부팅되고 나서 화면에 나타나는 로그인 메시지가 보이십니까? 그냥 text 기반의 메시지입니까? 아니면 그래픽 환경에서 로그인 메시지가 나옵니까? 대부분은 그래픽 환경에서 로그인 메시지가 보일 겁니다. 그 로그인 프로그램을 xdm(GNOME 환경은 gdm, KDE 환경은 kdm)이라고 하는데 그 프로그램은 X server를 이용하여 화면에 내용을 나타냅니다. 그런데 X server는 frame buffer device와 동일한 하드웨어, 즉 PC 상의 그래픽 카드를 사용하고 있기 때문에, frame buffer 프로그래밍을 위해서는 X server가 뜨지 말아야 합니다. 뭐 가장 간단한 방법으로 text 환경으로 나오려면 Ctrl+Alt+F2(2번째 virtual console)를 누르면 되지만 역시 X server가 back ground에서 수행되고 있는 상태이므로 이 정도로는 안됩니다. 그냥 부팅 당시부터 X server가 아예 뜨지 않도록 해야 합니다. 수단과 방법을 가리지 말고 X server가 뜨지 않게 만드시기 바랍니다.
그렇게 만드는 일이 어려운 분들이 있을까 봐 확실하고 원초적인(?) 방법을 공개합니다. 우선 /etc/inittab 파일을 editor로 여십시오.(물론 root권한이 있어야 바꿀 수 있으므로 root 권한 획득이 선행되어야 겠죠.) RedHat 기반의 linux 시스템(Wowlinux, Hancomlinux도 Redhat 기반일 겁니다.)이라면 다음과 같이 보일 겁니다.
=================================
<생략>
# Default runlevel. The runlevels used by RHS are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
id:5:initdefault:
<생략>
==================================
그럼 주석 부분을 살펴보면 “5 – X11”라고 되어 있고, “3 – Full multiuser mode”라고 되어있는 것을 확인합니다. (이 말은 5번이면 X11을 수행하여 xdm을 수행하고 3 이면 보통 multiuser 모드로 만든다는 이야기입니다.) 그런 다음 “id:5:initdefault”를 “id:3:initdefault”로 바꾸십시오. 그 다음 파일을 저장하고 rebooting합니다. 이제 xdm이 뜨지 않고 그냥 text 기반의 login 메시지가 보입니까? 지금까지 한 일을 좀 있어 보이는(?) 말로 default run-level을 5에서 3으로 바꾸었다라고 표현할 수 있습니다. 부팅하고 나서 다시 xdm이 실행되도록 하고 싶으면 당연히 원래대로 바꾸면 됩니다.
(사실 그냥 run time에 run-level을 바꿀 수도 있습니다. telinit이라는 프로그램이 있는데 위와 같은 변환을 telinit 3이라고 하면 그냥 3번 run-level로 바꿀 수 있습니다. 당연히 다시 run-level 5로 바꾸려면 telinit 5를 하면 되겠죠.)
== frame buffer module 올리기
(혹시 부팅화면 중에 펭귄 로고가 보입니까? 그렇다면 linux에 이미 frame buffer device driver가 올라가 있는 상태이므로 이 부분을 건너 뛰시기 바랍니다.)
이제 frame buffer module을 올릴 차례입니다. 당연히 module 안에는 frame buffer device driver가 있겠죠. 우선 자신이 가지고 있는 그래픽 카드가 무엇인지 알아야 합니다. 혹 모르는 사람은 쉘 상에 다음과 같은 명령어를 쳐서 나오는 화면을 보고 잘 생각해서 알아냅니다.
$ cat /proc/pci
(당연히 $은 쉘 프롬프트이므로 타이핑을 하지 말아야겠죠.)
자 시스템에 설치되어 있는 그래픽 카드가 무엇인지 알았으면 다음 차례로 넘어가죠.
어떤 frame buffer module 들이 있나 살펴보려면 /lib/modules/커널버젼/kernel/drivers/video 아래(하위 디렉토리 포함) 있는 모든 object 파일들을 살펴보면 됩니다. RedHat 8.0에 기본적으로 설치되는 frame buffer module은 다음과 같습니다.
==================================
aty/atyfb.o
matrox/i2c-matroxfb.o
matrox/g450_pll.o
matrox/matroxfb_DAC1064.o
matrox/matroxfb_Ti3026.o
matrox/matroxfb_accel.o
matrox/matroxfb_base.o
matrox/matroxfb_crtc2.o
matrox/matroxfb_maven.o
matrox/matroxfb_misc.o
riva/rivafb.o
aty128fb.o
clgenfb.o
fbcon-hga.o
fbcon-mfb.o
fbgen.o
hgafb.o
sis/sisfb.o
sstfb.o
mdacon.o
neofb.o
pm2fb.o
pm3fb.o
radeonfb.o
tdfxfb.o
==================================
각 파일들이 어떤 그래픽 카드와 매칭되는지 알아야 겠죠.
aty/atyfb.o : ATI mach64와 3D Rage 칩 기반의 카드
matrox/*.o : Matrox Millenium I, II, Mystique, G100, G200, G400, G450 칩 기반의 카드
riva/rivafb.o : nVidia RIVA 128/TNT/TNT2, Geforce 1, 2, 3 칩 기반의 카드
aty128fb.o : ATI Rage128 칩 기반의 카드
clgenfb.o : Cirrus Logic 칩 기반의 카드
sis/sisfb.o : SiS 300/630/730/540/315/550/650/740 칩 기반의 카드
sstfb.o : VOODOO 1, 2 칩 기반의 카드
neofb.o : NeoMagic Framebuffer(무엇인지 모름)
pm2fb.o: Permedia2 칩 기반의 카드
pm3fb.o : Permedia3 칩 기반의 카드
radeonfb.o : ATI Radeon(8500까지) 칩 기반의 카드
tdfxfb.o : VOODOO 3, 5, Banshee 칩 기반의 카드
나머지 파일은 무시해도 좋습니다.
이제 어떤 파일이 각자의 시스템에 달려 있는 그래픽 카드에 해당되는지 알았죠. 혹 가지고 있는 카드가 위의 리스트에 없다면 다음에 나올 “지원하는 frame buffer 없음”을 읽으시길 바랍니다.
글쓴이는 ATI mach64 칩을 사용한 그래픽 카드를 가지고 있으므로 다음과 같은 명령어로 module을 올리면 됩니다.(당연히 root 권한이 있어야 되겠죠.)
$ modprobe atyfb
(directory와 확장자는 떼어내야 합니다. matrox는 object가 많은데 어쩌냐구요? 저도 모릅니다. Matrox 그래픽 카드가 달려있는 linux 시스템에 없으므로 해 볼 수도 없고, 암튼 잘 해보시길… )
각자의 시스템에서 시스템에 맞는 module을 올려 보길 바랍니다. 그럼 화면이 깜박할 겁니다. 그럼 frame buffer module이 올라갔다고 보시면 됩니다.
== 지원하는 frame buffer 없음
가지고 있는 그래픽 카드가 위에서 언급한 칩에 해당되지 않는다면 이제는 어쩔 수 없이 VESA frame buffer를 올려야 합니다. 아주 아주 오래된 그래픽 카드가 아니라면 VESA BIOS 2.0 호환 그래픽 카드일 겁니다. VESA BIOS 2.0 호환 그래픽 카드를 지원하는 frame buffer driver는 보통 linux kernel에 built-in되어 있습니다. Kernel argument로 “vga=옵션”을 넘겨 주어서 초기화시킬 수 있다고 합니다. 자세한 내용은 다음과 같은 문서를 참고하시기 바랍니다.
(1) kernel 소스(Document/svga.txt)
(2) kernel 소스(Document/fb/vesafb.txt)
(3) Linux Framebuffer HOWTO(http://www.tldp.org/HOWTO/Framebuffer-HOWTO.html)
당연히 kernel argument를 바꾸려면 사용하고 있는 로더(보통 LILO 혹은 Grub이겠죠.)의 매뉴얼을 참고하시기 바랍니다. vesafb는 화면 해상도와 픽셀당 bit수 등을 run-time에 바꿀 수 없으니 픽셀당 bit수는 16bpp(bit per pixel)로 세팅하시기 바랍니다. (640x480@16bpp 권장)
(ATI mach 64 카드도 VESA BIOS 2.0 호환 카드로 알고 있는데 “vga=옵션”으로 vesafb를 올리는 시도를 한 결과 잘 되지 않더군요. 카드에 문제가 있을 수도 있지만 커널 컴파일을 새로 해야 할 지도 모른다는 생각이 듭니다. 그 vga kernel argument를 처리하는 부분은 arch/i386/boot/video.S 파일인 것으로 보이는데 RedHat 8.0 커널에서 그 파일의 처음 부분을 보면 “#undef CONFIG_VIDEO_SVGA”라고 되어 있습니다. 그런데 640x480x16bpp는 Standard VGA에서 지원하는 해상도와 bpp가 아니므로(즉 SuperVGA에서만 지원하므로) 잘 안 되는 것 같다는 의심이 듭니다. 암튼 정 안되면 여러가지를 바꿔보며 kernel compile을 새로 해보는 길 밖에 없을 것 같습니다. 뭐 이 문제로 질문이나 항의(?)가 많이 들어온다면 직접 해볼 수도 있겠지만 kernel compile하면 initrd도 새로 만들고 module도 새로 만들어야 하는데 상당히 귀찮습니다.)
== 마치며
이번 글에서는 각 시스템에 맞는 frame buffer module을 올리는 일을 알아봤습니다. 이제 다음 시간부터는 직접 프로그래밍을 해 볼 예정입니다. 우선 frame buffer driver의 정보(해상도와 bpp)를 알아보고 바꾸는 프로그램을 작성해 볼 생각이고, 점을 찍거나 읽는 루틴은 그 다음 글에서 알아볼 예정입니다.
== 관련 문서 및 소스 코드
(1) kernel 소스(Document/svga.txt)
(2) kernel 소스(Document/fb/*.txt)
(3) kernel 소스(drivers/video/*)
(4) Linux Framebuffer HOWTO(http://www.tldp.org/HOWTO/Framebuffer-HOWTO.html)
'Programming > Linux_Kernel' 카테고리의 다른 글
frame buffer 이야기 (3) (0) | 2009.06.04 |
---|---|
frame buffer 이야기 (2) (0) | 2009.06.04 |
udev debuging 방법 (0) | 2009.04.13 |
Linux kernel compile 시 stdio.h / stdlib.h 애러 (0) | 2009.01.21 |
Linux Kernel 의 spin lock (0) | 2009.01.13 |